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.

I'm looking for a more automated way to draw an area around a number of PStricks nodes. The area should be offset by a specific amount so that it will completely contain the vertices inside of it.

Here is a minimal example of a polygon that just traces the vertices/nodes:

enter image description here

\documentclass{article}
\usepackage{pst-node}% http://ctan.org/pkg/pst-node
\pagestyle{empty}
\begin{document}

\begin{pspicture}(0,0)(10,10)%
  \SpecialCoor
  % Identify some vertices
  \pnode(1;0){c}
  \pnode(1;300){g}
  \rput{0}([nodesep=1]c){
    \pnode(1;60){d}
    \pnode(1;0){e}
    \pnode(1;-60){f}
  }

  % Mark area
  \pspolygon[fillstyle=solid,fillcolor=black!15,linecolor=black!35,dimen=outer]
    (c)(d)(e)(f)(g)

  % Mark vertices
  \qdisk(c){3pt}
  \qdisk(d){3pt}
  \qdisk(e){3pt}
  \qdisk(f){3pt}
  \qdisk(g){3pt}
\end{pspicture}

\end{document}

The dimen=outer has no effect (and is used with \psframe), but it gives the idea that I'm after, just in a more general setting. From the pstricks documentation showing the effect of the dimen key-value (section 13 Line styles p 25):

enter image description here

My ideal solution would be something like offsetsep=5pt, akin to the offset key-value for regular lines (section 31 Node connections, p 68):

enter image description here

For example offsetsep=15pt will draw a polygon that is offset (outward) by 15pt, while offsetsep=-20pt will draw a polygon that is offset (inward) by 20pt.

share|improve this question

2 Answers 2

up vote 12 down vote accepted

How about this? This part uses a semi-automatic method to calculate the centroid.

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-eucl}
\psset{PointName=none}
\begin{document}
\begin{pspicture}[showgrid=false](-5,-5)(5,5)
\pnodes{A}(-2,3)(3,4)(2,-1)(-2,-4)(-4,0)
%
\def\points{(0,0)}
\def\Points{A0}% a dirty trick here
\foreach \x in {0,1,...,4}{%
    \pscircle*[linecolor=red](A\x){3pt}%
    \xdef\points{\points +0.2(A\x)}%
    \xdef\Points{\Points,A\x}%
}
\expandafter\nodexn\expandafter{\points}{O}
\pstHomO
[
    HomCoef=1.1,
    PointSymbol=none,
    CurveType=polygon,
    fillstyle=solid,
    fillcolor=cyan,
    opacity=0.25,
]{O}{\Points}
\end{pspicture}
\end{document}

enter image description here

Summary on dimen

I believe that you feel uncomfortable to remember the following notes as they are illogically defined so they waste your memory (in your brain).

For closed curves:

  1. psframe, pscircle, psellipse, pswedge, psellipticwedge have dimen=outer by default.
  2. the radial sides of pswedge and psellipticwedge always have dimen=middle, they cannot be changed.
  3. pspolygon, psccurve, and \pscustom always have dimen=middle, it cannot be changed.

For open curves:

  1. psline, pscurve, psbezier, psarc always have dimen=middle, they cannot be changed.
  2. psellipticarc has dimen=outer by default.

Animation

This part still uses the old method where the centroid is manually calculated.

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-eucl}
\psset{PointName=none,dotscale=2}
\begin{document}
\multido{\r=.6+.1}{8}{%
\begin{pspicture}[showgrid=false](-5,-5)(5,5)
\pnode(-.6,.4){O}
\pstGeonode
    (-2,3){A}
    (3,4){B}
    (2,-1){C}
    (-2,-4){D}
    (-4,0){E}
%
\pstHomO
[
    HomCoef=\r,
    PointSymbol=none,
    CurveType=polygon,
    fillstyle=solid,
    fillcolor=cyan,
    opacity=0.25,
    linearc=.2,
]{O}{A,B,C,D,E}
\end{pspicture}}
\end{document}

enter image description here

share|improve this answer
1  
No animation? :) Just kidding, +1 –  cmhughes Sep 16 '13 at 20:08
    
@cmhughes: Thanks for upvoting. Animation has been added. –  Please don't touch Sep 16 '13 at 20:16
    
Only for convex closed curves. –  Please don't touch Sep 16 '13 at 20:35
    
Does this require you to know the (x,y) centre of the object (I haven't experimented)? That is, can I draw some points willy-nilly for a polygon and expect it to scale proportionately without problem? The pst-eucl documentation just references it as the centre. Did you figure (-.6,.4) out manually? –  Werner Sep 16 '13 at 20:59
    
@Werner: For convex polygons, the their centroids can be used as the center of homotheti transformation. I calculated the centroid manually with simple formula (sigma x over number of points, sigma y over number of points). –  Please don't touch Sep 17 '13 at 4:47

Just for fun (cough) with TikZ (and PGF decorations).

The biggest part of the decoration code has already been provided by Mark Wilbrow in his answer to Draw additional parallel paths in TikZ. His decoration contour lineto works very fine but doesn’t deal with closed paths.

To work around this issue, the angle of the first segment (here (A) -- (B) is saved in \pgf@decorate@firstsegmentangle and later used if the input segment is a closepath/-- cycle.

If the contour line is drawn on the outer (longer) side of the polygon his code for the start state

\pgfpathmoveto{\pgfpoint{0pt}{\pgfdecoratedcontourdistance}}%

would have been fine but this point would lie on the outer side of a contour polygon that lies inside the original path. I don’t know a way to access the last segment’s angle to correct this in the very first state for the first segment. As a work-around the actual first segment of the contour line starts halfway between the first points (here, halfway between (A) and (B)).

This is sub-optimal. It is advised that the -- cycle operator actually travels a certain distance (so that an angle can be calculated). A path like

\path (0,0) -| (1,1) -| (0,0) -- cycle;

cannot be decorated successfully.

If the option rounded corners shall be used on the decorated contour line, the contour option (and rounded corners) has to be included in a pre- or postaction.

Code

\documentclass[tikz]{standalone}
\makeatletter
\usetikzlibrary{decorations,backgrounds}
\def\pgfdecoratedcontourdistance{0pt}
\pgfset{
  decoration/contour distance/.code=%
    \pgfmathsetlengthmacro\pgfdecoratedcontourdistance{#1}}
\pgfdeclaredecoration{contour lineto closed}{start}{%
  \state{start}[
    next state=draw,
    width=0pt,
    persistent precomputation=\let\pgf@decorate@firstsegmentangle\pgfdecoratedangle]{%
    \pgfpathmoveto{\pgfpointlineattime{.5}
      {\pgfqpoint{0pt}{\pgfdecoratedcontourdistance}}
      {\pgfqpoint{\pgfdecoratedinputsegmentlength}{\pgfdecoratedcontourdistance}}}%
  }%
  \state{draw}[next state=draw, width=\pgfdecoratedinputsegmentlength]{%
    \ifpgf@decorate@is@closepath@%
      \pgfmathsetmacro\pgfdecoratedangletonextinputsegment{%
        -\pgfdecoratedangle+\pgf@decorate@firstsegmentangle}%
    \fi
    \pgfmathsetlengthmacro\pgf@decoration@contour@shorten{%
      -\pgfdecoratedcontourdistance*cot(-\pgfdecoratedangletonextinputsegment/2+90)}%
    \pgfpathlineto
      {\pgfpoint{\pgfdecoratedinputsegmentlength+\pgf@decoration@contour@shorten}
      {\pgfdecoratedcontourdistance}}%
    \ifpgf@decorate@is@closepath@%
      \pgfpathclose
    \fi
  }%
  \state{final}{}%
}
\makeatother
\tikzset{
  contour/.style={
    decoration={
      name=contour lineto closed,
      contour distance=#1
    },
    decorate}}
\begin{document}
\begin{tikzpicture}
\path
    (-2, 3) coordinate (A)
    ( 3, 4) coordinate (B)
    ( 2,-1) coordinate (C)
    (-2,-4) coordinate (D)
    (-4, 0) coordinate (E);

\draw[preaction={contour=10pt, rounded corners, fill=gray}]
  (A) -- (B) -- (C) -- (D) -- (E) -- cycle;

\foreach \coord in {A,...,E} \fill (\coord) circle [radius=2pt];
\end{tikzpicture}

\begin{tikzpicture}[gridded, line width=.25cm, opacity=.75]
\draw                                           (0,2) rectangle (2,3);
\draw[contour=.5\pgflinewidth]  (0,0) rectangle (2,1);
\draw[contour=-.5\pgflinewidth] (3,0) rectangle (4,3);
\path[xshift=5cm,contour=.5\pgflinewidth,draw,line join=round]
  (0,0) -| (1,3) -- (2,1) -- (0,1) -- cycle;
\end{tikzpicture}
\end{document}

Output

enter image description here enter image description here

share|improve this answer
    
looks nice. Could you not also save the angle of the preceding segment? Then you could test if the current segment is a closepath and if it is and has length zero, use the previous angle? –  Mark Wibrow Sep 20 '13 at 7:26

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.