5

I have a simple cube in 3-space, 4 faces drawn in red and top and bottom in green.

 \documentclass[border=5,tikz]{standalone}

 \usepackage{tikz-3dplot}

 \begin{document}
 \foreach\s in{2,4,...,360}{
     \tdplotsetmaincoords{2.71828+\s}{2.71828+\s*2}
     \tikz[tdplot_main_coords,scale=.1]{
         \path(-15cm,-15cm)(15cm,15cm);
         \draw[ultra thick, color=black, fill=green!80!black]
             (0,0,0)--(20,0,0)--(20,20,0)--(0,20,0)--cycle        % bottom
             (0,0,20)--(20,0,20)--(20,20,20)--(0,20,20)--cycle;   % top
         \draw[ultra thick, color=black, fill=red!80!black]
             (0,0,0)--(20,0,0)--(20,0,20)--(0,0,20)--cycle
             (0,20,0)--(20,20,0)--(20,20,20)--(0,20,20)--cycle
             (0,0,0)--(0,20,0)--(0,20,20)--(0,0,20)--cycle
             (20,0,0)--(20,20,0)--(20,20,20)--(20,0,20)--cycle;
     }
 }

 \end{document}

that when seen from certain angles in TikZ, show an unexpected projection. It seems that when certain faces go on top of each other -- they become transparent!

enter image description here

Is this a bug, or there is something wrong with way the cube is built?

Paulo Ney
  • 2,405
  • Try \foreach\s in{2,4,...,360}{% \tdplotsetmaincoords{2.71828+\s}{2.71828+\s*2} \tikz[tdplot_main_coords,scale=.1]{% \path(-15cm,-15cm)(15cm,15cm); \draw[ultra thick, color=black, fill=green!80!black] (0,0,0)--(20,0,0)--(20,20,0)--(0,20,0)--cycle; % bottom \draw[ultra thick, color=black, fill=green!80!black] (0,0,20)--(20,0,20)--(20,20,20)--(0,20,20)--cycle; % top \draw[ultra thick, color=black, fill=red!80!black] (0,0,0)--(20,0,0)--(20,0,20)--(0,0,20)--cycle; cont.... – cfr Feb 24 '16 at 01:05
  • ... \draw[ultra thick, color=black, fill=red!80!black] (0,20,0)--(20,20,0)--(20,20,20)--(0,20,20)--cycle; \draw[ultra thick, color=black, fill=red!80!black] (0,0,0)--(0,20,0)--(0,20,20)--(0,0,20)--cycle; \draw[ultra thick, color=black, fill=red!80!black] (20,0,0)--(20,20,0)--(20,20,20)--(20,0,20)--cycle; }% } ;) – cfr Feb 24 '16 at 01:05
  • If it is a bug, I'm guessing it is in tikz-3dplot rather than TikZ. This rotated coordinate system stuff is from that package rather than pgf or tikz proper. (It could be a bug in TikZ, but there's no reason to assume that is so, even if it is a bug rather than just a limitation.) There is no doubt that TikZ really isn't designed to do this and tikz-3dplot already pushes the limits on what's doable, I think. Pushing them further... well, it isn't surprising it doesn't entirely work, I don't think. (Which isn't to say it is not a bug.) – cfr Feb 24 '16 at 01:12
  • @cfr I tried your code - it seems to be just a distribution of the \draw command for each one of the face separately! Well apparently it shows another bug: one of the edges is missing! – Paulo Ney Feb 24 '16 at 01:52
  • Indeed. Strange, no? – cfr Feb 24 '16 at 01:57
  • Which viewer is this? Did you try with Adobe Reader? – percusse Feb 24 '16 at 02:35
  • @percusse The missing edge on code show on Adobe Reader on Linux and Windows 10 as well as Edge viewer, and a conversion to GIF. – Paulo Ney Feb 24 '16 at 02:46
  • If you give each rectangle its own \draw, the fills are fine but some of the edges vanish. The OP is constructing a complex set of overlapping parallelograms then trying to fill the interior. It gets confused. – John Kormylo Feb 24 '16 at 03:58
  • @JohnKormylo Not sure how to interpret your comment. Confused on a cube!?!? It seems to be the best MWE to pursue this bug! – Paulo Ney Feb 24 '16 at 04:06
  • @PauloNey - what does it mean to fill two concentric circles at the same time? Fill both? Fill the outer but not the inner (which I believe is what Tikz would do). – John Kormylo Feb 24 '16 at 04:10
  • @JohnKormylo Circles??? Are you speaking figuratively? Should it be enclosed polygons? – Paulo Ney Feb 24 '16 at 04:19
  • @PauloNey - I am attempting to show by an easier example that filling overlapping shapes is not simple. There can be ambiguities. – John Kormylo Feb 24 '16 at 04:27
  • @JohnKormylo But these are NOT overlapping shapes -- they are the faces of a cube and the only overlap are the edges. It is true that their projection overlaps in the plane, but even then, one polygon colored green and another colored green on top -- with TikZ -- everything is green o the resulting intersection. – Paulo Ney Feb 24 '16 at 04:47
  • To avoid artifacts at vertices, add line join=round as option to \tikz command. – Paul Gaborit Feb 24 '16 at 07:07
  • 1
    The default filling rule is the nonzero rule and which bits end up empty in overlapping shapes in a single path is dependent on the path direction. See the manual "Graphic Parameters: Interior Rules". – Mark Wibrow Feb 24 '16 at 08:04
  • It should be mentioned that the filling is done in 2D using screen coordinates. – John Kormylo Feb 24 '16 at 19:12

1 Answers1

6

Because each rectangle is filled independently, none are treated as holes. For a solid, one needs to draw the faces from the far to near, or assign a normal vector and only draw faces pointing in this direction.

math here

\documentclass[border=5,tikz]{standalone}

% Uses \nearx, \neary and \nearz
% #1=x, #2=y, #3=z, #4={code to be executed}
\def\ifnear(#1,#2,#3)#4 
  {\pgfmathparse{#1*\nearx+#2*\neary+#3*\nearz}%
  \ifdim\pgfmathresult pt>0pt\relax #4\fi}

 \usepackage{tikz-3dplot}

 \begin{document}
 \foreach\s in{2,4,...,360}{
   \pgfmathsetmacro{\aTheta}{2.71828+\s}
   \pgfmathsetmacro{\aPhi}{2.71828+\s*2}
   \pgfmathsetmacro{\nearx}{sin(\aPhi)*sin(\aTheta)}
   \pgfmathsetmacro{\neary}{-cos(\aPhi)*sin(\aTheta)}
   \pgfmathsetmacro{\nearz}{cos(\aTheta)}
   \begin{tikzpicture}[scale=.1]
     \path(-15cm,-15cm)(15cm,15cm);
     \tdplotsetmaincoords{\aTheta}{\aPhi}
     \begin{scope}[tdplot_main_coords]
       \ifnear(0,0,-1){\draw[fill=green!80!black]
             (0,0,0)--(20,0,0)--(20,20,0)--(0,20,0)--cycle;}       % bottom
       \ifnear(0,0,1){\draw[fill=green!80!black]
             (0,0,20)--(20,0,20)--(20,20,20)--(0,20,20)--cycle;}   % top
       \ifnear(0,-1,0){\draw[fill=red!80!black]
             (0,0,0)--(20,0,0)--(20,0,20)--(0,0,20)--cycle;}
       \ifnear(0,1,0){\draw[fill=red!80!black]
             (0,20,0)--(20,20,0)--(20,20,20)--(0,20,20)--cycle;}
       \ifnear(-1,0,0){\draw[fill=red!80!black]
             (0,0,0)--(0,20,0)--(0,20,20)--(0,0,20)--cycle;}
       \ifnear(1,0,0){\draw[fill=red!80!black]
             (20,0,0)--(20,20,0)--(20,20,20)--(20,0,20)--cycle;}
     \end{scope}
   \end{tikzpicture}
 }

 \end{document}

If you reverse the signs on \nearx, \neary and \nearz it will show the other side of the cube.

The normal vector is a line perpendicular to the face and (for our purposes) pointing away from the center. For regular polyhedrals one can use the vector from the center of the object to the center of the face.

The center of the cube is at (10,10,10). Since the center of the bottom face was at (10,10,0), the (normalized) normal vector for that face was (0,0,-1).

John Kormylo
  • 79,712
  • 3
  • 50
  • 120
  • I see that the transparent part is gone, even though not all green faces are drawn correctly! Would you care to comment what your code is doing differently? As far as I can see in the manual they are supposed to be equivalent! – Paulo Ney Feb 24 '16 at 04:15
  • BTW, I added a direction test. – John Kormylo Feb 24 '16 at 18:41
  • Agreed that your new answer solves the problem of -- how to draw it! I even tried it on a more complex example (a truncated icosahedron from here: http://tex.stackexchange.com/questions/269108/truncated-icosahedron-in-tikz) and it works well. Would you be able to factor the \dotproduct test in a macro so we can use in a larger set of examples for test? But the larger question looms -- the first example I showed is almost certain a bug -- because any projection, filled from the back or not, should be a convex polygon in th end - with no holes! – Paulo Ney Feb 24 '16 at 20:58
  • @PauloNey Did you read the part of the manual Mark referred you to? TikZ is not filling/drawing a projection in 3D. It is filling/drawing a path in 2D. You are thinking in 3D terms, perhaps, whereas TikZ ONLY thinks in 2D terms. Maybe you could say that it is a bug in tikz-3dplot but I don't think that package claims to do away with the drawing-order requirement. At least, it probably shouldn't. The kind of manipulation you're talking about requires software which deals with 3D. Then your example should be trivial. But in 2D it is far from trivial. Does that make sense? – cfr Feb 24 '16 at 22:01
  • @cfr I have to disagree! This is NOT a problem of 3D at all. It is just a bunch of filled polygons drawn on top of one another and -- in this case -- the result should always be a convex polygon (no holes) -- and you can see it is not! Now on the issue of being a bug in TikZ vs. TikZ-3dplot it is hard to say because of how closely linked they are - I imagine all rendering is done by TikZ. And yes! I did read the Mark's reference! – Paulo Ney Feb 24 '16 at 22:26
  • @PauloNey They are not filled polygons when you draw/fill them as a single path. That's the point. If you fill/draw each polygon individually, then they are filled polygons. But when you fill/draw them as a single path, that is just not the case. That is how you think of them, fair enough. But that is not what you ask TikZ to draw. You give it a path and it has to figure out what you mean given that the path overlaps and intersects. If you draw/fill one polygon and then another, there are no holes. Because then you are asking for a bunch of filled polygons - unlike your original code. – cfr Feb 24 '16 at 23:17
  • @cfr You have a point! When you draw it as a long path, it may be swirling around and leaving some holes... Sorry for taking so long to recognize it!!! This is really what is going on here. So the only point left over now is your version -- that draws the faces one by one -- and it leaves one edge missing. – Paulo Ney Feb 24 '16 at 23:27
  • @PauloNey Is that explicable in terms of things being drawn in the wrong order? That would be my assumption. If you draw the wrong polygons first, the fill of later ones will go over the edges. That's why you have to draw the ones at the back before the ones in the front. That's what jon's answer is automating - it is figuring out which ones to draw first. At least, I think that's what it is doing. [Or figuring out which to draw at all....] – cfr Feb 24 '16 at 23:52
  • @cfr Yes! You are correct. That missing edge is just another face (a back one) being drawn in front of it. Thanks for insisting ... We probably should all leave TikZ-3D alone and move over to Asymptote. – Paulo Ney Feb 25 '16 at 00:25