3

I am making a simple 3d plot with asymptote and would like to have a nice arrow in the plot. I did manage to get an arrow in there, but it looks very asymmetric. I wish the top and bottom side of the arrow would have the same line width. Any ideas of how to accomplish that?

MWE plot

This image was generated with the following code:

settings.outformat = "png";
settings.render = 10;
settings.prc = false;
unitsize(1.0cm);
import three;
real width = 2.7;
real height = 1.6;
real depth = 1.2;
real lw = 2; //linewidth
currentprojection = obliqueX;

//define matplotlib default colors
pen C0 = RGB(31,119,180);
pen C3 = RGB(214,39,40);

//draw box
draw((0,0,0) -- (0,0,-height), C0+dashed+linewidth(lw));
draw((0,0,-height) -- (0,4*width,-height), C0+dashed+linewidth(lw));
draw((0,0,-height) -- (depth,0,-height), C0+dashed+linewidth(lw));
draw((0,0,0) -- (0,4*width,0), C0+linewidth(lw));
draw((depth,0,0) -- (0,0,0), C0+linewidth(lw));
draw((depth,0,-height) -- (depth,4*width,-height) -- (depth,4*width,0) -- (depth,0,0) -- (depth,0,-height), C0+linewidth(lw));
draw((depth,4*width,-height) -- (0,4*width,-height) -- (0,4*width,0) -- (depth,4*width,0), C0+linewidth(lw));
label("Box", (depth, 2*width, -0.40*height),C0);

//draw axis arrows
real axisZshift = -2.4;
real axisXshift = 0.2;
real axisLength = 1.0;
draw((0,axisZshift,axisXshift)--(-axisLength,axisZshift,axisXshift), arrow=Arrow3(TeXHead2(normal=Y)), L=Label("$z$", position=EndPoint, align=N+E));
draw((0,axisZshift,axisXshift)--(0,axisZshift,axisXshift+axisLength), arrow=Arrow3(TeXHead2(normal=X)), L=Label("$x$", position=EndPoint, align=N));
draw((0,axisZshift,axisXshift)--(0,axisZshift+axisLength,axisXshift), arrow=Arrow3(TeXHead2(normal=X)), L=Label("$y$", position=EndPoint, align=E));

//draw red arrow
draw((depth, 3.5*width, 1.5*height) -- (depth, 0.5*width, 1.5*height), arrow=Arrow3(TeXHead2, emissive(C3)), L=Label("red arrow", position=MidPoint, align=N), C3+linewidth(2*lw));
4

One way is to use a 2D arrows and 2D projection instead, by means of project() function:

settings.outformat = "png";
settings.render = 10;
settings.prc = false;
unitsize(1.0cm);
import three;
real width = 2.7;
real height = 1.6;
real depth = 1.2;
real lw = 2; //linewidth

currentprojection = obliqueX;

//define matplotlib default colors
pen C0 = RGB(31,119,180);
pen C3 = RGB(214,39,40);

//draw box
draw(project((0,0,0) -- (0,0,-height)            ), C0+dashed+linewidth(lw));
draw(project((0,0,-height) -- (0,4*width,-height)), C0+dashed+linewidth(lw));
draw(project((0,0,-height) -- (depth,0,-height)  ), C0+dashed+linewidth(lw));
draw(project((0,0,0) -- (0,4*width,0)            ), C0+linewidth(lw));
draw(project((depth,0,0) -- (0,0,0)              ), C0+linewidth(lw));
draw(project((depth,0,-height) -- (depth,4*width,-height) -- (depth,4*width,0) -- (depth,0,0) -- (depth,0,-height)), C0+linewidth(lw));
draw(project((depth,4*width,-height) -- (0,4*width,-height) -- (0,4*width,0) -- (depth,4*width,0)), C0+linewidth(lw));
label("Box", project((depth, 2*width, -0.40*height)),C0);

//draw axis arrows
real axisZshift = -2.4;
real axisXshift = 0.2;
real axisLength = 1.0;
draw(project((0,axisZshift,axisXshift)--(-axisLength,axisZshift,axisXshift )), arrow=Arrow(TeXHead), L=Label("$z$", position=EndPoint, align=N+E));
draw(project((0,axisZshift,axisXshift)--(0,axisZshift,axisXshift+axisLength)), arrow=Arrow(TeXHead), L=Label("$x$", position=EndPoint, align=N));
draw(project((0,axisZshift,axisXshift)--(0,axisZshift+axisLength,axisXshift)), arrow=Arrow(TeXHead), L=Label("$y$", position=EndPoint, align=E));

//draw red arrow
draw(project((depth, 3.5*width, 1.5*height) -- (depth, 0.5*width, 1.5*height)), arrow=Arrow(TeXHead), L=Label("red arrow", position=MidPoint, align=N), C3+linewidth(2*lw));

enter image description here

To simplify the process, you can also define some functions like

void draw(guide3 g, pen p){
  draw(project(g),p);
};

Then , for example, the commands like

draw((0,0,0) -- (0,0,-height), C0+dashed+linewidth(lw));

will draw a projection automatically.

2
  • Thanks a lot, it sure looks beautiful! However, it also means that I need to project everything, which can be a bit cumbersome in larger projects, even with your great void draw(...) example. So I will wait a bit longer to see if someone has a simpler answer before accepting your helpful answer. – laolux Nov 18 '20 at 7:30
  • So, I got it to work in a larger example, but it is very unfortunate that project(...) does not work together with 3d stuff. So, I need to rearrange my figures according to what gets drawn behind what, as projected figures will not take into account 3 dimensionality anymore. :-| – laolux Nov 19 '20 at 3:18

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.