3

How can I offset a hobby curve, so that the resulting curve serves as a shifted and parallel outline to the original curve? Here is what I got so far:

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

\usepackage{tikz}
\usetikzlibrary{calc,hobby}

\tikzset{
    point/.style={circle,inner sep=0pt,minimum size=3pt,fill=red},
}

\begin{document}
\begin{tikzpicture}
\coordinate [label=below right:$A$] (A) at (0,0);
\coordinate [label=above right:$B$] (B) at (0,-5);
\coordinate [label=above left:$C$] (C) at (2.5,-3);
\coordinate [label=above left:$D$] (D) at (5,-2);
\coordinate [label=below left:$E$] (E) at (4.5,0);

\draw (A) -- (B);
\draw ([out angle=0]B) to [curve through ={(C)}] ([in angle=-135]D);
\draw (D) -- (E);
\draw (E) -- (A);

\draw[blue,dashed] (A) -- ([xshift=-.3cm]A);
\draw[blue,dashed] ([xshift=-.3cm]A) -- ([xshift=-.3cm]B);
\draw[blue,dashed] ([xshift=-.3cm]B) to[out=-90,in=180] ([yshift=-.3cm]B);
\draw[blue,dashed] ([out angle=0,yshift=-.3cm]B) to [curve through ={([yshift=-.3cm]C)}] ([in angle=-135,yshift=-.3cm]D);

\node[point] at (A) {};
\node[point] at (B) {};
\node[point] at (C) {};
\node[point] at (D) {};
\node[point] at (E) {};
\end{tikzpicture}
\end{document}

Which produces the following image: curves

As you can see, the blue-dashed line from A to B is 0.3cm apart from the original line. However, the blue-dashed curve does not maintain a constant distance from the original curve.

I tried the solution from JLDiaz in this post and that works perfectly, as long as you don't use hobby curves, because they don't seem to support the coordinate[pos=xxx] option that is used in the solution. Using regular curves instead of hobby curves is not an option for me, since the hobby curves produce a much nicer "flow".

I figure that shifting something around in parallel is such a common task, that there must be an easier way of doing it, right? Can anyone point me into the right direction?

  • I don't think there's an easy way in PGF/TikZ unless some enterprising soul has published a package since the last time a question along these lines was asked. PGF/TikZ has certain limitations. I think this is one of them. – cfr May 16 '16 at 11:24
  • Ok, is there a hard way then? – snorge May 16 '16 at 20:21
  • You can save and restore a Hobby path but you need to know how you want to transform it and I don't think you know that. Not in TikZ terms. – cfr May 16 '16 at 23:33
  • Well, you are right. I already experimented with save and restore but there is no way to transform the path so that it maintains a constant distance to the original one. Especially if the original path has turns greater than 90 degrees. That is really unfortunate and kinda makes me want to turn away from TikZ and use something else. Are MetaPost or PSTricks capable of outlining curves? Do these packages support hobby curves? – snorge May 17 '16 at 7:10
  • Actually, when I come to think about it, it would help tremendously, if the hobby package would support the coordinate[pos=xxx] option. Then I could use the solution of JLDiaz that is linked above. I'm just wondering, if it would be that hard to implement that option. – snorge May 17 '16 at 9:22
3

Without a fairly sizeable amount of work, the best TikZ can do by default is something like this. It's almost there, but frustratingly tricky to get the kinks ironed out.

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{calc,hobby,decorations}
\tikzset{
   point/.style={circle,inner sep=0pt,minimum size=3pt,fill=red},
}
\begin{document}
\begin{tikzpicture}
\coordinate [label=below right:$A$] (A) at (0,0);
\coordinate [label=above right:$B$] (B) at (0,-5);
\coordinate [label=above left:$C$] (C) at (2.5,-3);
\coordinate [label=above left:$D$] (D) at (5,-2);
\coordinate [label=below left:$E$] (E) at (4.5,0);

\draw
  (A) -- (B) to [out angle=0, in angle=-135, curve through=(C)]
  (D) -- (E) -- cycle;

\draw [decoration={curveto, raise=-0.3cm}, decorate, blue, dashed]
  (A) -- (B) to [out angle=0, in angle=-135, curve through=(C)]
  (D) -- (E) -- cycle;

\foreach \n in {A,...,E}
  \node[point] at (\n) {};
\end{tikzpicture}
\end{document}

enter image description here

However, bearing in mind the caveats from this answer, here is a decoration for out-setting which not really very efficient and will probably fail for paths where the exterior angle between consecutive paths is acute or the interior angle is very small. But it is at least passable for the current example. The basic idea is to extend each path at the corners with a straight line similar to the approach taken in mitering. It might give the metapost-guys some ideas ;)

enter image description here

  • Thanks, I did not know about the raise option. Exactly what I wanted, except for the corners. But I guess fixing them is the kind of trickiness you meant when you talked about ironing out the kinks. Nice approach though, thank you very much! – snorge May 17 '16 at 15:22
1

This is an oddly fiddly task. I've tried to produce a robust solution to this problem a couple of times without ever getting a very satisfactory or general result. But here is my latest effort. This is in Metapost but it might give the tikz-guys some ideas.

enter image description here

Compile with mpost...

prologues := 3;
outputtemplate := "%j%c.eps";

beginfig(1);

numeric u;  u = 1cm;
path shape;  
shape = ( origin -- (0,-5) { right } .. (5/2,-3) .. { dir 45 } (5,-2) -- (9/2,0) -- cycle ) scaled u;

draw shape; 
for t=0 upto 4: 
  fill fullcircle scaled 3 shifted point t of shape withcolor red;
  label(char (65+t), 6 up rotated angle direction t+1/16 of shape shifted point t+1/16 of shape);
endfor

path C; C = fullcircle scaled 20; 
numeric a, b, s; s=1/4; 
draw for t=s step s until length shape:
    hide(
        a := directiontime (point t of shape - precontrol t of shape) of C;
        b := directiontime (postcontrol t of shape - point t of shape) of C;
        if b<a: a:= a-8; fi
        % uncomment this draw command to see the contruction circles...
        % draw C shifted point t of shape withcolor .8[red,white];
    )
    subpath (a,b) of C shifted point t of shape {direction t+eps of shape} ..
endfor cycle dashed evenly;

endfig;
end.

The idea here is to use the pre-control and post-control points of each step along the path to define an appropriate arc of a circle and then connect up all of these arcs. Where the three control points are in a line this arc will be a single point (which is what we want). Reducing the step size improves the shape of the surrounding curve, but if you go too small you get some extra loop artefacts. This is what I mean about it not being a very robust approach. But I hope it provides at least some inspiration.

And while I'm at it, there is another technique you could try: drawing with a fat pen, and then erasing the interior.

beginfig(2);
  draw shape withpen pencircle scaled 12 withcolor blue;
  undraw shape withpen pencircle scaled 11;
  unfill shape;
  draw shape;
endfig;

with shape defined as in the first figure this produces:

enter image description here

but don't try adding a dash pattern with such a fat pen, it will look very strange. The unfill shape gets rid of the line inside the shape.

  • Nice! Metapost is definitely better at curves than TiKZ generally, I think. (I guess this makes sense in terms of origins and purpose.) What does the +eps do? The trouble is, I find Metapost code harder to read than TikZ - even when it is my own code. Probably just haven't practised enough, I guess ;). – cfr May 17 '16 at 12:54
  • @cfr eps is a numeric constant defined in plain.mp. It's supposed to be a small amount that's still sort-of noticeable, and not quite as small as epsilon which is the smallest number plain MP allows. eps:=1/2048; epsilon:=1/256/256. The point of adding it is to avoid calling direction at the turns. – Thruston May 17 '16 at 13:26
  • Thanks! Because of the similarity to .eps, I was very confused! – cfr May 17 '16 at 13:36
  • This looks really nice. Thank you for your effort! Now I need to learn MetaPost... ;) – snorge May 17 '16 at 15: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.