# Draw solid cylinder with asymptote

I want to draw an image like this with asymptote, but I don't know how to draw the cylinder part like in this image.

I try with this code

``````triple v=O;
real cyl_r=2;
real cyl_h=3;
triple axis=Z;
axis = X;
revolution r = cylinder(v, cyl_r, cyl_h, axis);
r = shift(-0.5*cyl_h,-ho,lf)*r;
// draw(surface(r),green,render(merge=true));
draw(r);
``````

But the result is not as I expected, the cylinder is not solid

I want the cylinder image same as the first image

• I suggest you to use ipe.otfried.org
– user213378
Commented Jun 6, 2020 at 8:25

To have solid cylinders and silhouette you have to mix the 3D OpenGL (unitcylinder, unitsphere, etc...) and the `solids` package (to have silhouette of your cylinder). For the construction I have created one function which draws a cylinder (solid and silhouette) and another function (a simple loop) to avoid a very long list of `triple` and axis. The code is not perfect, there is one warning because I use the silhouette function.

``````import three;
import solids;
size3(10cm);
currentprojection=orthographic(600,450,200);

triple v=O;
real cyl_r=.4;
real cyl_h=.7;
triple axis=Z;

void cyl_oriented_shifted(triple pO=v, real r=cyl_r, real h=cyl_h, triple maxis=Z)
{
// v should be the center
// if maxis=O there is no cylinder, not very elegant
if (maxis!=O)
{
surface cylinder=shift(pO)*align(unit(maxis))*shift((0,0,-cyl_h/2))*scale(cyl_r,cyl_r,cyl_h)*unitcylinder;
surface disq_cyl=shift(pO)*align(unit(maxis))*shift((0,0,-cyl_h/2))*scale(cyl_r,cyl_r,cyl_h)*unitdisk;
surface disq_cyl1=shift(pO)*align(unit(maxis))*shift((0,0,cyl_h/2))*scale(cyl_r,cyl_r,0)*unitdisk;
revolution rcyl = cylinder(pO-h/2*unit(maxis), r, h, maxis);
material whitem =  material(diffusepen=white,emissivepen=white);
draw(cylinder,whitem,render(merge=true));
draw(disq_cyl,whitem);
draw(disq_cyl1,whitem);
draw(rcyl,black+1bp);
}
}

void sequence_of_node_and_segment (triple [] T, triple [] AT, pen p1=currentpen)
{
// T is the array of node
// AT the array of associated axis for the cylinders or not if AT[i]==O
for (int i=0;i<T.length;++i)
{
cyl_oriented_shifted(T[i],cyl_r,cyl_h,AT[i]);
if (i<T.length-1)
{ // the segment
draw(T[i]--T[i+1],p1);
}
}
}

pen pentige=black+2bp;
// lower part
triple[] RL={(0,0,0),(0,0,1), (2,0,4),(0,0,8),(0,3,8),(2,3,4),(0,3,1),(0,3,0)};
triple[] ARL={O,Y,Y,Y,Y,Y,Y,O};
sequence_of_node_and_segment(RL,ARL,pentige);

// arms
triple[] HRL={(0,-1.5,11), (0,-1.5,13.3),(0,-1.5,14),(0,0,14),(0,3,14),(0,4.5,14),(0,4.5,13.3),(0,4.5,11)};
triple[] AHRL={Y,X,O,Y,Y,O,X,Y};
sequence_of_node_and_segment(HRL,AHRL,pentige);

// to the upper part
triple[] HC={(0,1.5,8), (0,1.5,10),(0,1.5,14),(0,1.5,15.6)};//,(0,0,13),(0,3,13),(0,4.5,13),(0,4.5,12),(0,4.5,10)};
triple[] AHC={O,Z,Z,Y};
sequence_of_node_and_segment(HC,AHC,pentige);

draw(shift((0,1.5,8))*scale3(.2)*unitsphere,material(diffusepen=white,emissivepen=white));
revolution sph=sphere((0,1.5,8),.2);
draw(sph.silhouette(),black+1bp);
``````

and the result. Please notice that the picture is not vectorized since the true 3D OpenGL renderer is used.

• Hi, @O.G. I have just test your code. I just paste your code to the webpage: asymptote.ualberta.ca, it looks like the generated image is not the same as the one in the answer. Half of the cylinder is not shown. I change the line to `draw(cylinder,whitem); //,render(merge=true));`, then it works OK. Here are two questions: 1, what dose the `render` argument in your code used for? 2, why there is a check of `maxis!=O` , what does the parameter `maxis` used for? Thanks. Commented Apr 21, 2022 at 6:55
• I guess that the `maxis` is the direction of the axis of the cylinder. So, this vector should not be zero, am I correct? Commented Apr 21, 2022 at 7:02
• @ollydbg23 : I proposed this code two years ago (and I have no answer). I have no idea about your question, only that the option `merge` is related to Bezier patches. Sorry. For `maxis`, you're right !
– O.G.
Commented Apr 27, 2022 at 19:17

I'm taking the liberty of reviving this discussion to present a library using Asymptote, of which I am the author, to create a kinematic diagram using French normalised symbols. You can find it at https://github.com/ameurdefroid/biblioLiaisons3D2D The documentation is in French, but the content is explained in pictures. If it finds an international audience, I can translate it if necessary. For the example in this discussion, the code is :

``````// Settings pdf
settings.render = -4 ;
settings.prc = false ;

// Package + stage
import biblioLiaisons ;
defaultpen(fontsize(10pt));
unitsize(1cm);
triple eye = (1,1,1) ;
triple up = (0,1,0) ;
currentprojection = orthographic(eye, up, O) ;
currentlight = nolight;

// Parameters
real a = 1 ;
real b = 2 ;
real c = 5 ;
real theta = 20/360*2*pi ;

// basis
basis b1 = rotationBasis(1, b0, theta, 'x', b0.x) ;
basis b2 = rotationBasis(2, b0, -theta, 'x', b0.x) ;

// Points
triple O1 = a*b0.y ;
triple O2 = O1 + b*b0.z ;
triple A = O2 +  a*b0.y ;
triple B = A - b*b0.z ;
triple C = B + c*b1.y ;
triple D = C + c*b2.y ;

// CEC
pen CEC0 = black ;
pen CEC1 = red ;
pen CEC2 = green ;
pen CEC3 = blue ;
pen CEC4 = magenta ;

// Features
and the result is shown in the left figure. But we've got a joint to describe two revolutions: "rotule à doigt" `liaisonRotuleDoigt(B, b0.y, b0.x, CEC2, CEC0) ;` (right figure).