Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

In this answer, Jake points out

The miter option is more "correct" in that it doesn't add new corners to a shape or introduce rounding. In some cases with very sharp angles, the results might be undesirable though, as in the question you linked to...

in reference to this question. It's certainly true that for very acute angles, a mitered joint will extend far beyond the coordinate where the two lines intersect. In some sense, this is because TikZ draws lines centered on the specified coordinates, which is almost always the desired result. But in this circumstance, it might be better to specify the outermost point of the miter as the "endpoint" of the lines, and have the strokes be entirely uncentered and to one side of the coordinates or the other. Illustrator (for example, because I have it handy) supports this, but only for closed paths, where there is a well-defined "inside" and "outside" to the path. For an acute angle, you could reuse "inside" or "outside" in a semi-sensical way, but that terminology may not generalize to single lines... For lack of better terminology then, I'll reuse "above" or "below" or "left" or "right", as are used to describe label positioning.

Is there a convenient way in TikZ to specify lines as being drawn "above" or "below" their coordinates---effectively being offset by exactly half the line-thickness in the direction perpendicular to the line? And is there a similar solution for drawing curves "above" or "below" their coordinates (not as easy to say "perpendicular to the line", though still mathematically possible)? If there isn't a good solution for arbitrary open paths, is there a good one for closed paths, as in Illustrator?

EDIT: To answer Andrew's question, Illustrator draws the following path by default, "inside" and "outside":

Illustrator's path-stroke options

The top path is selected, which is drawn in blue highlighting. That stroke is "default", or centered. The middle is "inside", and draws the two subregions separately. The bottom is "outside". Here's a twistier, more self-intersecting example, that shows Illustrator has a miter limit, as well as an algorithm that seems to be parity-based:

twisty paths

Note that Illustrator limits "inside" and "outside" to solid strokes on closed paths only: if you attempt a dashed stroke, or have a non-closed path, or try tiger-striping like in Andrew's example, it disables the inside and outside options, which makes me wonder whether there happens to be a convenient PDF or PS command for offsetting simple strokes on simple paths, rather than a more robust solution...

I completely agree that the choice of side is not local, but on the other hand if you pick a single option for the first segment of the path (e.g., "to the right side, when headed from the first point on the path to the second"), it will stay consistent for the rest of the path.

The original question that prompted mine was the attempt to draw a cube in 3d with thickened edges. I was curious whether you could draw said cube by saying, "Draw the front face, stroked inside. Draw the (foreshortened) top face, stroked inside. Draw the (foreshortened) side face, stroked inside." In that scenario, Andrew's twisty paths don't come up and there still is a well-defined inside and outside, and the goal would be to have pointy corners as befits a cube, so the mitering would need to be specified by the outermost points...

EDIT: To follow-up on my commented question to Andrew's answer, here's what TikZ makes of his solution as applied to the figure-eight example he gave. The paths here are drawn in a figure-eight, starting in the direction of the arrow. They use the reverseclip style from this answer, and the exact path used is drawn in color over the clipped versions:

Tikz clipping of figure-eight paths

The red example uses clipping, and gets the "inside" to match Illustrator's behavior...but the blue example uses reverse clipping, and gets confused in the right half of the image. If I draw the figure-eights in the other orientation, then the red example stays the same, but the blue example gets confused on the left half of the image. And finally, the exact same styles, but using the "twisty" path I had above:

Tikz clipping of twisty paths

Both the red and blue paths are slightly confused, and while they don't follow Illustrator's even-odd algorithm, I have no idea what algorithm the are following...

(And finally, the TikZ code for the twisty paths I used, for anyone who wants to reproduce the behavior I'm seeing:

\documentclass{article}
%\url{http://tex.stackexchange.com/q/29991/86}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}[remember picture,overlay,scale=2,line width=2mm]
\tikzstyle{reverseclip}=[insert path={(current page.north east) --
  (current page.south east) --
  (current page.south west) --
  (current page.north west) --
  (current page.north east)}
]
\draw (0,1) -- (1,0) -- (4,2) -- (1,1) -- (4,1) -- (3,0) -- (1,2) -- (2.5,0) -- cycle;
\draw[green,line width=1pt] (0,1) -- (1,0) -- (4,2) -- (1,1) -- (4,1) -- (3,0) -- (1,2) -- (2.5,0) -- cycle;
\begin{scope}[yshift=-2.5cm,line width=4mm]
\begin{scope}
\clip (0,1) -- (1,0) -- (4,2) -- (1,1) -- (4,1) -- (3,0) -- (1,2) -- (2.5,0) -- cycle;
\draw (0,1) -- (1,0) -- (4,2) -- (1,1) -- (4,1) -- (3,0) -- (1,2) -- (2.5,0) -- cycle;
\end{scope}
\draw[red,line width=1pt] (0,1) -- (1,0) -- (4,2) -- (1,1) -- (4,1) -- (3,0) -- (1,2) -- (2.5,0) -- cycle;
\end{scope}
\begin{scope}[yshift=-5cm,line width=4mm]
\begin{pgfinterruptboundingbox}
\path[clip] (0,1) -- (1,0) -- (4,2) -- (1,1) -- (4,1) -- (3,0) -- (1,2) -- (2.5,0) -- cycle [reverseclip];
\draw (0,1) -- (1,0) -- (4,2) -- (1,1) -- (4,1) -- (3,0) -- (1,2) -- (2.5,0) -- cycle;
\end{pgfinterruptboundingbox}
\draw[blue,line width=1pt] (0,1) -- (1,0) -- (4,2) -- (1,1) -- (4,1) -- (3,0) -- (1,2) -- (2.5,0) -- cycle;
\end{scope}
\end{tikzpicture}
\end{document}
share|improve this question
1  
It's worth pointing out that TikZ automatically switches from miter to bevel joins if the angle between two line segments is too small, to prevent the line from extending too far past the specified coordinates. The threshold can be adjusted using miter limit=<number>. –  Jake Sep 30 '11 at 4:01
    
Illustrator is doing String Topology!! –  Loop Space Sep 30 '11 at 13:02
    
More seriously, I can't guess from that what Illustrator is doing. It is certainly playing fast and loose with the concept of "path" so TikZ might have trouble copying it. It seems more likely that it is filling the paths in some complicated way, then redrawing them, and then refilling them. –  Loop Space Sep 30 '11 at 13:03
    
On the whole, I think I'd rather have a go at drawing the cube you describe that the general case. Would that be okay? –  Loop Space Sep 30 '11 at 13:05
    
@AndrewStacey, yes, the general case does seem a bit tricky to even define well! My understanding of Illustrator's behavior is: rather than "left" or "right" side, it uses the even-odd rule to determine inside or outside, then strokes accordingly. (If you overlap the second two pictures, they never both color a pixel black.) The filled polygons are degenerate cases where 2*strokewidth > polygon width. The cube is an example where the "inside" is topologically simple and intuitively clear, so that'd be a good starting point for the OP question. –  Ben Lerner Sep 30 '11 at 19:15

4 Answers 4

up vote 8 down vote accepted

I was idling thinking how one might go about this, when I came up with a very simple solution. I wouldn't be surprised to learn that this is what Illustrator does. Looking at the diagrams, it would seem that way.

My initial plan was to figure out some sort of decoration that would "shift" a path to the left or right, but that just seemed fraught with difficulties. But I couldn't think of a way to get TikZ to treat the two halves of a path in a different manner. Then I realised that there is such a way: clipping.

When TikZ clips against a path then the two sides of that path are treated in a different manner. So that can be used to get it to only draw one side. Sort of. You draw a path, but clip it against itself. Since the clipping path has no width, this means that half the path gets drawn. The "Sort of" is because the decision about which half depends on the region that is being enclosed, not the actual side of the path. This, I think, leads to the funny look on the Illustrator images in the question.

A general solution to this would involve a command to draw and clip in the same breath. That could be done with my spath library (still in development, but available from the TeX-SX site on launchpad), and one would have to use the "reverse" clip method from somewhere around here for dealing with the other side. But to demonstrate the concept, we can just do it by hand. Here's the cube:

Cube with clipping

and here's the code:

\documentclass{article}
%\url{http://tex.stackexchange.com/q/29991/86}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}[scale=5,line width=2mm]
\draw (0,0,0) -- (1,0,0) -- (1,1,0) -- (0,1,0) -- cycle;
\draw (1,0,0) -- (1,0,-1) -- (1,1,-1) -- (1,1,0) -- cycle;
\draw (0,1,0) -- (0,1,-1) -- (1,1,-1) -- (1,1,0) -- cycle;
\begin{scope}[yshift=-2cm,line width=4mm]
\begin{scope}
\clip (0,0,0) -- (1,0,0) -- (1,1,0) -- (0,1,0) -- cycle;
\draw (0,0,0) -- (1,0,0) -- (1,1,0) -- (0,1,0) -- cycle;
\end{scope}
\begin{scope}
\clip (1,0,0) -- (1,0,-1) -- (1,1,-1) -- (1,1,0) -- cycle;
\draw (1,0,0) -- (1,0,-1) -- (1,1,-1) -- (1,1,0) -- cycle;
\end{scope}
\begin{scope}
\clip (0,1,0) -- (0,1,-1) -- (1,1,-1) -- (1,1,0) -- cycle;
\draw (0,1,0) -- (0,1,-1) -- (1,1,-1) -- (1,1,0) -- cycle;
\end{scope}
\end{scope}
\end{tikzpicture}
\end{document}

Note the scopes to limit the clips, and the doubled line width, since we lose half of it in the clip.

share|improve this answer
    
I like that! Clipping a path against itself to get the "inside" of it -- clever :) What result do you get if you try it on the figure-eight example from your prior answer? Presumably the "inside" is less easily defined? (Incidentally, the even-odd rule is considered "simple" by graphics folks, even if it leads to rather unintuitive images at first! It is used by Illustrator and Freehand, and can be used in SVG or PS images, etc.) –  Ben Lerner Oct 1 '11 at 0:28
    
This answers the question as stated, though not the trickier, fuzzier general case. Shall I hold off on accepting this answer until your spath solution is available, until you've taken a crack at the general case, or accept this as it stands? –  Ben Lerner Oct 1 '11 at 0:32

This is really a comment, but I want to post a picture. In the spirit of "A picture paints a thousand words ...", can you tell me what Illustrator considers to be the inside and outside of this path:

Mobius strip

I realise that you say "where there is a well-defined "inside" and "outside" to the path", so presumably Illustrator can't cope with that example. The point I wish to make is that the request is not a local one: you can't consistently define the "inside" and "outside" of an arbitrary path. When you examine a particular join, you have to take into account all of the other pieces of the path to work out what should happen.

An alternative would be to have TikZ always adjust the join to shift it to the inner angle. This would work as it is a local property, and the fact that the function is not continuous at \pi/2 wouldn't matter because you'd never notice the discontinuity (it's a rare picture that has a family of lines converging at one point from a whole range of angles, and for that you could just turn off the facility). However, I don't think that that would solve the basic problem. The join would still look as bad, it would just be shifted. Here's a cheap example of what you'd get:

enter image description here

(Cheap because it has the outer path as well, this was done using the double option.) The inner line looks just as awful as the outer line.

There comes a point in any diagram or document where the computer has to say, "Here's my best shot." and the person has to look at the result and say, "That's not quite what I wanted, let me adjust things a little.". I think you've just reached that point. One of the great things about TeX (and thus, by extension, TikZ) is that when you want the autopilot to turn off and for you to resume manual control, it does so gracefully and elegantly.

(As I said at the start, this is a comment, not an answer. I'm sure that someone could implement something that did this automatically and it would be an awesome bit of code.)

share|improve this answer

One approach is to use path decorators. They do not look at inside or outside, but on the direction in which the path is drawn.

This is not exactly what the original poster asks about, but this could be the start of a solution. See example and code below.

An example of what is possible using path decorators.

http://www.texample.net/tikz/examples/lipid-vesicle/

share|improve this answer

Mixed solutions with good result:

enter image description here

The code:

\documentclass[margin=4mm]{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[line width=4mm,even odd rule]
  \tikzset{invclip/.style=
    {clip,insert path={(-16000pt,-16000pt) rectangle (16000pt,16000pt)}}%
  }
  % some paths to try...
  % \def\mypath{(0,1) -- (1,0) -- (4,2) -- (1,1) -- (4,1) -- (3,0) -- (1,2) -- (2.5,0) -- cycle}
  %\def\mypath{(0,0) -- (1,-1) -- (3,1) -- (4,0) -- (3,-1) -- (1,1) -- cycle}
  \def\mypath{(0,0) -- (1,1) -- (3,-1) -- (4,0) -- (3,1) -- (1,-1) -- cycle}
  % normal
  \draw \mypath;
  \draw[green,line width=1pt] \mypath;
  % inside
  \begin{scope}[yshift=-2.5cm,line width=4mm]
    \begin{scope}
      \clip \mypath;
      \draw \mypath;
    \end{scope}
    \draw[red,line width=1pt] \mypath;
  \end{scope}
  % outside
  \begin{scope}[yshift=-5cm,line width=4mm]
    \begin{pgfinterruptboundingbox}
      \path[invclip] \mypath;
      \draw \mypath;
    \end{pgfinterruptboundingbox}
    \draw[blue,line width=1pt] \mypath;
  \end{scope}
\end{tikzpicture}
\end{document}

Result with your "twisty" path:

enter image description here

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.