5

This question led to a new package:
rputover

In brief, I'm looking for a version of \rput* that blocks out lines but not fill colors.

Specifically, I would like to create an image of the following type

label obscuring line but not background colors

I can do that by coding the broken vertical line as two separate \pslines, like so

\documentclass{article}
\usepackage{pstricks}
\pagestyle{empty}
\begin{document}
\begin{pspicture}(2,2)
\psframe[fillstyle=solid,fillcolor=blue!40,linestyle=none](0,0)(2,2)
\pscurve[fillstyle=solid,fillcolor=red!30,linestyle=none](0,2)(1,1)(2,2)
\psline(1,0)(1,0.7)
\psline(1,1.2)(1,2)
\rput(1,1){\Large\sf label}
\end{pspicture}
\end{document}

But I'd like to replace those two lines with one (\psline(1,0)(1,2)) and use something like \rput*(1,1){\color{black}\Large\sf label}, which would obviate the need to calculate the point at which the line has to be broken and allow me to move the label around without recalculating the positions of the ends of the line segments. The problem with \rput* is that it creates a white background.

Is there a variant of \rput* that does the job?

2
  • to me this seems to be a bit difficult because the command would have to `guess' which objects you'd like to block out and which not. – user121799 Feb 14 '17 at 4:05
  • @marmot I'd like to block all lines and no fills. However, I don't know whether the distinction between the two can be detected by Postscript. – Martin J. Osborne Feb 14 '17 at 4:16
4

You can change the order of drawing:

\documentclass{article}
\usepackage{pst-node}
\pagestyle{empty}
\begin{document}
    \begin{pspicture}(2,2)
    \pcline(1,0)(1,2)\ncput*{\Large\sf label}
    \psframe*[linecolor=blue,opacity=0.3](0,0)(2,2)
    \pscurve*[linecolor=red,opacity=0.3](0,2)(1,1)(2,2)
    \end{pspicture}
\end{document}

enter image description here

2
  • Very nice, but the disadvantage of course is that the colors cover the label; if the label color is white, it is covered completely. – Martin J. Osborne Feb 14 '17 at 15:19
  • yes, an automatic solution is not possible – user2478 Feb 14 '17 at 15:42
3

There is no such variant. However, the calculation can be automated rather than estimated manually.

Using pst-node you can place an object inside \psDefBoxNodes{<node name>}{<object>}. This would enable one to access bounding box (and other) nodes. The node identification for \psDefBoxNodes{Age}{\color{red!50}\sffamily \"Age} (from the pst-node documentation) reveals:

enter image description here

With the above information you can draw the \psline to <node>:tB and from <node>:tC as the y coordinates:

enter image description here

\documentclass{article}

\usepackage{pst-node}

\begin{document}

\begin{pspicture}(2,2)
  \psframe[fillstyle=solid,fillcolor=blue!40,linestyle=none](0,0)(2,2)
  \pscurve[fillstyle=solid,fillcolor=red!30,linestyle=none](0,2)(1,1)(2,2)  
  \psline(1,0)(1,0.7)
  \psline(1,1.2)(1,2)
  \rput(1,1){\Large\sffamily label}
\end{pspicture}

\begin{pspicture}(2,2)
  \psframe[fillstyle=solid,fillcolor=blue!40,linestyle=none](0,0)(2,2)
  \pscurve[fillstyle=solid,fillcolor=red!30,linestyle=none](0,2)(1,1)(2,2)  
  \rput(1,1){\psDefBoxNodes{label}{\Large\sffamily label\strut}}
  \psline(1,0)(1,0|label:bC)
  \psline(1,0|label:tC)(1,2)
\end{pspicture}

\end{document}

Note that the text included \strut to ensure the spacing above/below whatever is included in the label spans the regular \baselineskip.

8
  • Very cool! I like a variant that puts padding of the same width on all sides of the box containing the text. I have implemented that with the code \rput(1,1){\psDefBoxNodes{label}{\fbox{\Large\sffamily label}}} and the settings \fboxrule=0pt \fboxsep=2pt (for example). (I'm not sure if that is the best way to do it.) – Martin J. Osborne Feb 14 '17 at 15:12
  • Working on it it a bit more ... This technique deals very nicely with the specific example. But if the line over which the label is placed does not go through the nodes of the box, I don't see how to do it. For example, what if the black line is an arbitrary curve? – Martin J. Osborne Feb 14 '17 at 15:29
  • Is it possible to get the coordinates of the corners of the pspicture? If so, then something like the following may work: replace the three lines starting with \rput in your solution with \rput(1,1){\psDefBoxNodes{label}{\fbox{\Large\sffamily label}}} \psclip{\pspolygon[linestyle=none](0,0)(0,2)(2,2)(2,0)(0,0)(label:bl)(label:br)(label:tr)(label:tl)} \psline(0,0)(2,2) \pscurve[linecolor=blue](1,0)(1.5,0.5)(0.5,1.5)(1,2) \endpsclip. If it is possible to get the coordinates of the corners of the pspicture then the hard-coded coordinates in \psclip could be avoided. – Martin J. Osborne Feb 14 '17 at 20:52
  • @MartinJ.Osborne: It is possible to get the coordinates of the pspicture environment, yes. They're hidden (by default) in the dimensions (xll,yll)(xur,yur) = (\pst@dima,\pst@dimb)(\pst@dimc,\pst@dimd) (and made sure that \pst@dima < \pst@dimc and \pst@dimb < \pst@dimd, in case the use inputs it "incorrectly"). See this paste. I guess one could make them more accessible to the end user so it's not readily required to use \makeatletter... – Werner Feb 15 '17 at 17:49
  • If the user changes the origin using \psset{origin={x,y}}, I need to adjust the clip area. Is it possible to get the coordinates (x,y)? – Martin J. Osborne Feb 18 '17 at 20:15
2

It seems to me that the following solution is a counterexample to @Herbert's claim that "an automatic solution is not possible" ... It is based on (i) @Werner's answer, (ii) my proposal to use \psclip in a comment on his answer, and (iii) his subsequent response.

\rputover has exactly the same format as \rput, but its content covers any objects in the argument of \coverable.

\documentclass{article}
\usepackage{pstricks,pst-node}

\makeatletter

\newcounter{pstfiglabel}

\def\rputover{%
    \@ifnextchar[%
          {\@ifnextchar({\@putoveror}{\@putoveron}}
          {\@ifnextchar({\@putovernn}{\@putovernr}}
}

\def\@putoveror[#1]#2(#3,#4)#5{%
  \rput[#1]{#2}(#3,#4){\psDefBoxNodes{label\thepstfiglabel}{\fbox{#5}}}
  \stepcounter{pstfiglabel}%
}

\def\@putoveron[#1](#2,#3)#4{%
  \rput[#1](#2,#3){\psDefBoxNodes{label\thepstfiglabel}{\fbox{#4}}}
  \stepcounter{pstfiglabel}%
}

\def\@putovernr#1(#2,#3)#4{%
  \rput{#1}(#2,#3){\psDefBoxNodes{label\thepstfiglabel}{\fbox{#4}}}
  \stepcounter{pstfiglabel}%
}

\def\@putovernn(#1,#2)#3{%
  \rput(#1,#2){\psDefBoxNodes{label\thepstfiglabel}{\fbox{#3}}}
  \stepcounter{pstfiglabel}%
}

\def\coverable#1{%
  \newcounter{coverable}
  \psclip{%
    \pscustom[linestyle=none,fillstyle=solid]{
      \loop
        \psline[liftpen=2](label\thecoverable:bl)(label\thecoverable:br)(label\thecoverable:tr)(label\thecoverable:tl)(label\thecoverable:bl)
        \stepcounter{coverable}
        \ifnum\value{coverable}<\value{pstfiglabel}
      \repeat
      \psline[liftpen=2](-\maxdimen,-\maxdimen)(-\maxdimen,\maxdimen)(\maxdimen,\maxdimen)(\maxdimen,-\maxdimen)
      }%
    }%
    #1
  \endpsclip
}

\makeatother

\begin{document}

\begin{pspicture}(2,2)
\fboxrule=0pt
\fboxsep=2pt
\psframe[fillstyle=solid,fillcolor=blue!40,linestyle=none,linewidth=0pt](0,0)(2,2)
\pscurve[fillstyle=solid,fillcolor=red!30,linestyle=none](0,2)(1,1)(2,2)

\rputover(1,1){\sffamily label}%
\rputover{45}(1.6,1.6){\sffamily label}%
\rputover[l](.5,0.5){\sffamily label}%

\coverable{
  \psline(0,0)(2,2)
  \pscurve[linecolor=blue](1,0)(1.5,0.5)(0.5,1.5)(1,2)
  \psline(1,0)(2,2)
}

\end{pspicture}
}

\end{document}

The output follows.

enter image description here

Here's how it works. \rputover, in addition to doing an \rput, also gets the coordinates of the object being put. \coverable clips out of the objects in its argument the boxes containing the objects in the \rputovers, leaving 'holes' for these objects. If you replace \pscustom[linestyle=none] with \pscustom[linestyle=none,fillstyle=solid] in the definition of \coverable you will see the clip area, as in the following image.

enter image description here

2
  • @Herbert, @Werner I have improved my answer, which originally required the user to specify a label for each object in the argument of '\rputover'. (The labels are used only internally, and are now created by the script.) In addition, \rputover now accepts an alignment argument and a rotation argument, exactly like \rput. So I believe it qualifies as 'a version of \rput* that blocks out lines but not fill colors.' – Martin J. Osborne Feb 17 '17 at 1:09
  • @Werner I was wondering whether that was permitted ... I have also improved the solution by using \maxdimen in the clip path, as you suggested. – Martin J. Osborne Feb 20 '17 at 20:45

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.