# Planes' intersection in Asymptote

The code:

\documentclass{article}
\usepackage{asymptote}
\begin{document}
\begin{asy}
//================ Format =================
settings.outformat = "pdf";
settings.prc = false;
settings.render = 0;
import three;
import bsp;
texpreamble("\usepackage{euler,beton}");
size(5cm, 0);
currentprojection=orthographic((5,4,3));
//================ Drawing ===================
path3 pl =plane((0,-2,0),(-2,0,0),(0,1,0));
path3 pl1=rotate(-28,X)*pl;
path3 pl2=rotate(-56,X)*pl;
path3 pl3=shift(-0.3*normal(pl1))*pl1;

triple[] asd=intersectionpoints(pl2,pl3);
triple A=asd[1];
triple B=asd[0];

triple[] asf=intersectionpoints(pl,pl2);
triple C=asf[1];
triple D=asf[0];

triple[] asg=intersectionpoints(pl,pl3);
triple E=asg[1];
triple F=asg[0];

face[] faces;

filldraw(faces.push(pl),project(pl),  white+opacity(0.6));
filldraw(faces.push(pl1),project(pl1),white+opacity(0.6));
filldraw(faces.push(pl2),project(pl2),white+opacity(0.6));
filldraw(faces.push(pl3),project(pl3),white+opacity(0.6));

draw(B--A);
draw(C--D);
draw(E--F);

dot(A,red);
dot(B,red);
dot(C,red);
dot(D,red);
dot(E,red);
dot(F,red);

\end{asy}

If I add the following labeling at the very end of the code above:

label("$A$",A,S);
label("$B$",B,S);
label("$C$",C,S);
label("$D$",D,S);
label("$E$",E,S);
label("$F$",F,S);
\end{asy}

\end{document}

Asymptote produses this:

Question #1: Why does it shift the points?

Question #2: How to make the line CD be "covered" by the plane? So, I want it to look like the invisible edges of the planes: not the whole CD, but the only invisible part of it.

• Please always post complete code people can compile! – cfr Nov 14 '16 at 3:44

Note that I know nothing about Asymptote.

# Caveat emptor ...

This answer is almost exclusively drawn from Charles Staats's fantastic tutorial and the interested reader is encouraged to look there for further details and more correct advice!

If you use settings.render=0, then Asymptote draws things in the order they are given i.e. pretty much as if we were in 2D TikZ. So, setting settings.render to some other value is required for the plane to 'cover' stuff layered below.

These should also probably really be surfaces, I guess, perhaps with no light.

\documentclass{article}
\usepackage{asymptote}
\begin{document}
\begin{asy}
settings.outformat = "pdf";
settings.prc = false;
settings.render = 16;
import three;
import bsp;
texpreamble("\usepackage{euler,beton}");
size(5cm, 0);
currentprojection=orthographic((5,4,3));

path3 pl =plane((0,-2,0),(-2,0,0),(0,1,0));
path3 pl1=rotate(-28,X)*pl;
path3 pl2=rotate(-56,X)*pl;
path3 pl3=shift(-0.3*normal(pl1))*pl1;

draw (pl);
draw (pl1);
draw (pl2);
draw (pl3);

triple[] asd=intersectionpoints(pl2,pl3);
triple A=asd[1];
triple B=asd[0];

triple[] asf=intersectionpoints(pl,pl2);
triple C=asf[1];
triple D=asf[0];

triple[] asg=intersectionpoints(pl,pl3);
triple E=asg[1];
triple F=asg[0];

surface s1=surface(pl);
draw(s1,white+opacity(.6),light=nolight);
surface s2=surface(pl1);
draw(s2,white+opacity(.6),light=nolight);
surface s3=surface(pl2);
draw(s3,white+opacity(.6),light=nolight);
surface s4=surface(pl3);
draw(s4,white+opacity(.6),light=nolight);

draw(B--A);
draw(C--D);
draw(E--F);

dot(A,red);
dot(B,red);
dot(C,red);
dot(D,red);
dot(E,red);
dot(F,red);

//From Charles Staats's tutorial
//Direction of a point toward the camera.
triple cameradirection(triple pt, projection P=currentprojection) {
if (P.infinity) {
return unit(P.camera);
} else {
return unit(P.camera - pt);
}
}

//Move a point closer to the camera.
triple towardcamera(triple pt, real distance=1, projection P=currentprojection) {
return pt + distance * cameradirection(pt, P);
}

label("$A$",align=NE,position=towardcamera((A)));
label("$B$",align=S,position=towardcamera((B)));
label("$C$",align=SE,position=towardcamera((C)));
label("$D$",align=SE,position=towardcamera((D)));
label("$E$",align=NE,position=towardcamera((E)));
label("$F$",align=S,position=towardcamera((F)));
\end{asy}

\end{document}

# EDIT

If you simply must have vector graphics - a restriction which was not mentioned in the question - then you need to take care of the drawing order yourself. This requires splitting each surface into pieces and reassembling them according to their position relative to other pieces.

Here is an example rendered with settings.render=0 to ensure vector output.

The diagram on the right uses colouring to demonstrate that the drawing order is (as far as I can tell) correct. The version on the left is identical except that it uses white in place of the colours for the surfaces and does not specify a colour for the drawn outlines.

\documentclass{article}
\usepackage{asymptote}
\begin{document}
\begin{asy}
settings.outformat = "pdf";
settings.prc = false;
settings.render = 0;
import three;
import bsp;
texpreamble("\usepackage{euler,beton}");
size(5cm, 0);
currentprojection=orthographic((5,4,3));

path3 pl =plane((0,-2,0),(-2,0,0),(0,1,0));
path3 pl1=rotate(-28,X)*pl;
path3 pl2=rotate(-56,X)*pl;
path3 pl3=shift(-0.3*normal(pl1))*pl1;

triple[] asd=intersectionpoints(pl2,pl3);
triple A=asd[1];
triple B=asd[0];

triple[] asf=intersectionpoints(pl,pl2);
triple C=asf[1];
triple D=asf[0];

triple[] asg=intersectionpoints(pl,pl3);
triple E=asg[1];
triple F=asg[0];

path3 q11=(D -- -Y -- C-Y -- C -- cycle);
surface sq11=surface(q11);
draw(sq11,white+opacity(.6),light=nolight);
draw(D -- -Y -- C-Y -- C--cycle);

path3 q21=rotate(-28,X)*q11;
surface sq21=surface(q21);
draw(sq21,white+opacity(.6),light=nolight);
draw(rotate(-28,X)*(D -- -Y -- C-Y -- C -- cycle));

path3 q31=(D--C--A--B--cycle);
surface sq31=surface(q31);
draw(sq31,white+opacity(.6),light=nolight);
draw(D--C--A--B--cycle);

path3 q34=(C -- D -- rotate(-56,X)*(D+Y) -- rotate(-56,X)*(C+Y) -- cycle);
surface sq34=surface(q34);
draw(sq34,white+opacity(.6),light=nolight);
draw(C -- D -- rotate(-56,X)*(D+Y) -- rotate(-56,X)*(C+Y) -- cycle);

path3 q22=(C -- D -- rotate(-28,X)*(D+Y) -- rotate(-28,X)*(C+Y) -- cycle);
surface sq22=surface(q22);
draw(sq22,white+opacity(.6),light=nolight);
draw(C -- D -- rotate(-28,X)*(D+Y) -- rotate(-28,X)*(C+Y) -- cycle);

path3 q12=(D -- C -- E -- F -- cycle);
surface sq12=surface(q12);
draw(sq12,white+opacity(.6),light=nolight);
draw(q12);

surface s4=surface(pl3);
draw(s4,white+opacity(.6),light=nolight);
draw(pl3);

path3 q32=(rotate(-56,X)*(D-Y) -- rotate(-56,X)*(C-Y) -- A -- B -- cycle);
surface sq32=surface(q32);
draw(sq32,white+opacity(.6),light=nolight);
draw(rotate(-56,X)*(D-Y) -- rotate(-56,X)*(C-Y) -- A -- B -- cycle);

path3 q13=(Y -- C+Y -- E -- F -- cycle);
surface sq13=surface(q13);
draw(sq13,white+opacity(.6),light=nolight);
draw(Y -- C+Y -- E -- F -- cycle);

dot(A,red);
dot(B,red);
dot(C,red);
dot(D,red);
dot(E,red);
dot(F,red);

//From Charles Staats's tutorial
//Direction of a point toward the camera.
triple cameradirection(triple pt, projection P=currentprojection) {
if (P.infinity) {
return unit(P.camera);
} else {
return unit(P.camera - pt);
}
}

//Move a point closer to the camera.
triple towardcamera(triple pt, real distance=1, projection P=currentprojection) {
return pt + distance * cameradirection(pt, P);
}

label("$A$",align=NE,position=towardcamera((A)));
label("$B$",align=S,position=towardcamera((B)));
label("$C$",align=SE,position=towardcamera((C)));
label("$D$",align=SW,position=towardcamera((D)));
label("$E$",align=NE,position=towardcamera((E)));
label("$F$",align=S,position=towardcamera((F)));
\end{asy}
\begin{asy}
settings.outformat = "pdf";
settings.prc = false;
settings.render = 0;
import three;
import bsp;
texpreamble("\usepackage{euler,beton}");
size(5cm, 0);
currentprojection=orthographic((5,4,3));

path3 pl =plane((0,-2,0),(-2,0,0),(0,1,0));
path3 pl1=rotate(-28,X)*pl;
path3 pl2=rotate(-56,X)*pl;
path3 pl3=shift(-0.3*normal(pl1))*pl1;

triple[] asd=intersectionpoints(pl2,pl3);
triple A=asd[1];
triple B=asd[0];

triple[] asf=intersectionpoints(pl,pl2);
triple C=asf[1];
triple D=asf[0];

triple[] asg=intersectionpoints(pl,pl3);
triple E=asg[1];
triple F=asg[0];

path3 q11=(D -- -Y -- C-Y -- C -- cycle);
surface sq11=surface(q11);
draw(sq11,red+opacity(.6),light=nolight);
draw(D -- -Y -- C-Y -- C--cycle,red);

path3 q21=rotate(-28,X)*q11;
surface sq21=surface(q21);
draw(sq21,blue+opacity(.6),light=nolight);
draw(rotate(-28,X)*(D -- -Y -- C-Y -- C -- cycle),blue);

path3 q31=(D--C--A--B--cycle);
surface sq31=surface(q31);
draw(sq31,green+opacity(.6),light=nolight);
draw(D--C--A--B--cycle,green);

path3 q34=(C -- D -- rotate(-56,X)*(D+Y) -- rotate(-56,X)*(C+Y) -- cycle);
surface sq34=surface(q34);
draw(sq34,green+opacity(.6),light=nolight);
draw(C -- D -- rotate(-56,X)*(D+Y) -- rotate(-56,X)*(C+Y) -- cycle,green);

path3 q22=(C -- D -- rotate(-28,X)*(D+Y) -- rotate(-28,X)*(C+Y) -- cycle);
surface sq22=surface(q22);
draw(sq22,blue+opacity(.6),light=nolight);
draw(C -- D -- rotate(-28,X)*(D+Y) -- rotate(-28,X)*(C+Y) -- cycle,blue);

path3 q12=(D -- C -- E -- F -- cycle);
surface sq12=surface(q12);
draw(sq12,red+opacity(.6),light=nolight);
draw(q12,red);

surface s4=surface(pl3);
draw(s4,yellow+opacity(.6),light=nolight);
draw(pl3,yellow);

path3 q32=(rotate(-56,X)*(D-Y) -- rotate(-56,X)*(C-Y) -- A -- B -- cycle);
surface sq32=surface(q32);
draw(sq32,green+opacity(.6),light=nolight);
draw(rotate(-56,X)*(D-Y) -- rotate(-56,X)*(C-Y) -- A -- B -- cycle,green);

path3 q13=(Y -- C+Y -- E -- F -- cycle);
surface sq13=surface(q13);
draw(sq13,red+opacity(.6),light=nolight);
draw(Y -- C+Y -- E -- F -- cycle,red);

dot(A,red);
dot(B,red);
dot(C,red);
dot(D,red);
dot(E,red);
dot(F,red);

//From Charles Staats's tutorial
//Direction of a point toward the camera.
triple cameradirection(triple pt, projection P=currentprojection) {
if (P.infinity) {
return unit(P.camera);
} else {
return unit(P.camera - pt);
}
}

//Move a point closer to the camera.
triple towardcamera(triple pt, real distance=1, projection P=currentprojection) {
return pt + distance * cameradirection(pt, P);
}

label("$A$",align=NE,position=towardcamera((A)));
label("$B$",align=S,position=towardcamera((B)));
label("$C$",align=SE,position=towardcamera((C)));
label("$D$",align=SW,position=towardcamera((D)));
label("$E$",align=NE,position=towardcamera((E)));
label("$F$",align=S,position=towardcamera((F)));
\end{asy}
\end{document}
• I have read that and know this trick. 1) settings.render = 16; is not an option because the picture is not a vector graphics any more. Vector graphics is a publisher's requirement. So settings.render = 0 is that I need to have. I think that the solution does exist anyway as my approach was also (surely) stolen from asymptote tutorial (very last paragraph of the three-module description), and it keeps the graphics vector. 2) The code above doesn't work being copied in the blank isolated new document. – Sergey Belyaev Nov 14 '16 at 11:20
• @SergeyBelyaev 1) If you need vector, then you have to ensure things are drawn in the correct order as that's the order Asymptote uses. The tutorial indicates there are some tricky workarounds but doesn't say what they are. 2) It works fine for me. What does 'doesn't work' mean? Do you get an error? Which? Does it look different? How? Just saying it doesn't work for you when it works for me means I can't possibly say anything helpful. – cfr Nov 14 '16 at 16:50
• Basically, you will need to draw and fill the planes in parts in order to get the order right. Or create parts of the surfaces in the appropriate order. Obviously it works to produce vector. But you asked why things which should be behind other things weren't hidden or partly hidden. That's because you have settings.render=0 and don't take care things are drawn and filled in the required order. So either you change settings.render or you take care of the order yourself. At least, those are the options as I understand them. – cfr Nov 14 '16 at 16:55
• Log file exited normally. When I compile, TeXStudio's viewer says: "Failed to find ...path/document.pdf; perhaps it has been deleted. But I have just copied and pasted it into he new document.tex and compiled. So the issue is still unclear. – Sergey Belyaev Nov 14 '16 at 20:26
• Thank you for the suggestion to change the order of the lines drawn. I have really tried, but nothing changes. I put all draw commands before the plane drawing commands in my code above and nothing changes. I mean, it compiles unerroneously, but that is not the result we are trying to achieve. I also have read about this secret tricks Charles notes in his tutorial. Probably, I should write to him directly. – Sergey Belyaev Nov 14 '16 at 20:26