# Drawing Ellipsoids in Asymptote; Camera too Close

I am trying to draw a set of Ellipsoids in Asymptote which are given by an symmetric positive definite matrix or in other words by three vectors v1,v2,v3 of length 1 forming an ONB (the ellipsoids main axes) and their lengths l1,l2,l3

\documentclass[12pt]{scrartcl}
\usepackage{asypictureB}
\begin{document}
\begin{asypicture}{name=AsyTest}
import three;
import settings;

surface ellipsoid(triple v1,triple v2,triple v3,real l1,real l2, real l3, triple pos=O) {
transform3 T = identity4;
T = l1*v1.x;
T = l1*v1.y;
T = l1*v1.z;
T = l2*v2.x;
T = l2*v2.y;
T = l2*v2.z;
T = l3*v3.x;
T = l3*v3.y;
T = l3*v3.z;
T = pos.x;
T = pos.y;
T = pos.z;
return T*unitsphere;
}

size(9cm);

currentprojection=perspective(4.5,4,-11,Z, (4.5,4,0));

draw(ellipsoid( (1,0,0), (0,1,0), (0,0,1), 0.2, 0.3, 0.4, O), rgb(0,1,0));
\end{asypicture}
\end{document}


The function should be able to scale and shift the unitsphere and hence creating an ellipsoid given by the above values and a center point pos, where the third to last line is an MWE for a green ellipsoid.

The perspective should look from below into the middle of all my ellipsoids (yep 9x8field here).

However the above Code resembles a Camera too close error, even if i move it far far away (replace -11by -100 say).

What's the reason for that? Any ideas?

One thing i noticed by creating the MWE: Removing l3 from the transform3 T, i.e. keeping v3 at unit length makes this file compile. Nevertheless i need to scale all 3 axes (which in general are of course no the unit axis as in this MWE).

• Interesting observation: It works for l3=0.595, but not for l3=0.59. – Charles Staats Feb 28 '15 at 20:59
• If you use the default perspective projection, you can get down to l3=0.55 without error, but still get the same camera too close error with l3=0.5. – Charles Staats Feb 28 '15 at 21:01
• Moving the camera much farther away does not appear to make much difference, but switching to an orthographic projection does. – Charles Staats Feb 28 '15 at 21:02
• Intersting observations! I'll check tomorrow for the whole field, whether the orthographic will look okay, i took the prespective just because i was used to that :) I won't mind the orthographic if it works with all its occlusions. – Ronny Feb 28 '15 at 21:14

## 1 Answer

Final solution

The problem is that by setting T = identity4, you are really making T an alias for identity4, so that changes to T are reflected in identity4. It's surprising this does not screw up more things than it does.

A correct version may be obtained by initializing T to be a copy of identity4:

transform3 T = copy(identity4);


The full code:

\documentclass[12pt]{scrartcl}
\usepackage{asypictureB}
\begin{document}
\begin{asypicture}{name=AsyTest}
import three;
import settings;

surface ellipsoid(triple v1,triple v2,triple v3,real l1,real l2, real l3, triple pos=O) {
transform3 T = copy(identity4);
T = l1*v1.x;
T = l1*v1.y;
T = l1*v1.z;
T = l2*v2.x;
T = l2*v2.y;
T = l2*v2.z;
T = l3*v3.x;
T = l3*v3.y;
T = l3*v3.z;
T = pos.x;
T = pos.y;
T = pos.z;
return T*unitsphere;
}

size(9cm);

currentprojection=perspective(4.5,4,-11,Z, (4.5,4,0));

draw(ellipsoid( (1,0,0), (0,1,0), (0,0,1), 0.2, 0.3, 0.4, O), rgb(0,1,0));
\end{asypicture}
\end{document}


## The following edits are maintained for historical reasons only.

Update 2

Here is a truly minimal (non-)working example of the problem (as an asy file, to show that the issue is intrinsic to Asymptote and not related to the TeX embedding):

import three;
transform3 T = identity4;
T = 0.4;
draw(unitsphere);


The result is an error:

/usr/local/texlive/2014/texmf-dist/asymptote/three.asy: 2903.30: camera too close


I have filed a bug report.

Update

After further research, I've found something truly bizarre. Somehow, the mere fact of computing T as you do is causing the error, regardless of whether the computation is used for anything.

The error shows up for the definition

surface ellipsoid(triple v1,triple v2,triple v3,real l1,real l2, real l3, triple pos=O) {
transform3 T = identity4;
T = l1*v1.x;
T = l1*v1.y;
T = l1*v1.z;
T = l2*v2.x;
T = l2*v2.y;
T = l2*v2.z;
T = l3*v3.x;
T = l3*v3.y;
T = l3*v3.z;
T = pos.x;
T = pos.y;
T = pos.z;

/*transform3*/ T = scale(l1, l2, l3);
return T*unitsphere;
}


but not for the definition

surface ellipsoid(triple v1,triple v2,triple v3,real l1,real l2, real l3, triple pos=O) {
/*transform3 T = identity4;
T = l1*v1.x;
T = l1*v1.y;
T = l1*v1.z;
T = l2*v2.x;
T = l2*v2.y;
T = l2*v2.z;
T = l3*v3.x;
T = l3*v3.y;
T = l3*v3.z;
T = pos.x;
T = pos.y;
T = pos.z;
*/
transform3 T = scale(l1, l2, l3);
return T*unitsphere;
}


These two should give exactly the same result; the only difference is that the first one does the computation of T (and then overwrites it), while the second does not do the computation.

Bottom line: I'm clueless as to where this error is coming from.

The problem appears to be that you are incorrectly constructing the transform3 matrix, with the result that the sphere is being blown up to something astronomically huge. So the error thrown by Asymptote is legitimate.

I have not gone through the reasoning about how the matrix is constructed, but I have two pieces of evidence that, taken together, strongly suggest the my conclusion.

First: For your particular test case, the major axes are simply the standard basis, so--if I understand correctly what you are doing--this example ought to give the same result if you define ellipsoid function by

surface ellipsoid(triple v1,triple v2,triple v3,real l1,real l2, real l3, triple pos=O) {
transform3 T = scale(l1, l2, l3);
return T*unitsphere;
}


However, with this definition, the file compiles with no problems. So there is almost certainly an error in your logic defining the transform3.

Second: Although it initially appears that moving the viewpoint farther away makes no difference, this is not quite correct--it's just that very small changes in l3 can make astronomical differences in the size of the ellipsoid. But I was able to find a boundary case by setting l3=0.591:

currentprojection=perspective((4.5,4,-11), up=Z, (4.5,4,0));
draw(ellipsoid( (1,0,0), (0,1,0), (0,0,1), 0.2, 0.3, 0.591, O), rgb(0,1,0));


does not compile, but if you multiply the camera distance by tenfold

currentprojection=perspective(10*(4.5,4,-11), up=Z, (4.5,4,0));
draw(ellipsoid( (1,0,0), (0,1,0), (0,0,1), 0.2, 0.3, 0.591, O), rgb(0,1,0));


it does compile.

• Thanks for the investigation, i reduced the basis to the unit vectors for the MWE, a more realistic call would be like ellipsoid( (0.26865,-0.064339,0.96109), (-0.9537,-0.15783,0.25602), (-0.13522,0.98537,0.10376), 0.51182, 0.2709, 0.24786, (0,0,0) ), - but the basis is normalized (by MatLab). Concerning transform3 you may be right, i couldn't find any documentation of the internal definition of that data type... – Ronny Feb 28 '15 at 22:02
• @Ronny: I assumed that the scale option would not be sufficient for you in general, but it made a useful comparison for the MWE. However, as you will see in my update, I am retracting my original answer--there is something truly bizarre going on here. Somehow the mere fact of computing T as you do is causing the error, regardless of whether the computation is used. And that makes no sense at all. – Charles Staats Feb 28 '15 at 22:18
• But in your Update you're performing the scaling twice once in the lines of my definition and once using scale? Maybe the error really already occurs when defining T like I do, not when applying it to unitsphere. But i couldnÄt find any other way to define a T, when you know the transformation matrix and the shift. – Ronny Feb 28 '15 at 22:23
• @Ronny: The second definition should overwrite the first, not be composed with it. In any case, I agree with you that it ought to be possible to define T as you do, and it makes no sense that it is causing an error--especially this particular error. – Charles Staats Feb 28 '15 at 22:32
• Yay! You found the problem. Nevertheless it's really not a bug. I wanted to ask that on SF and did some research. Actually (and i don't know why they keep that) transform T = identity4; will give you the reference to the identity (in R3 w/ homogeneous coordinates), which will mess up a lot of things. While copy(...); looks a little clumsy, the way it's used in three.asy is actually transform3 T = identity(4);, which gives you a copy of the identity. Somehow I forgot the () and surprisingly that messes things up like... alot. – Ronny Mar 1 '15 at 9:41