# How to draw smooth curves with PSTricks?

Consider the following example:

\documentclass{article}

\usepackage{pstricks-add}

\begin{document}

\begin{pspicture}(0,-0.25)(4,6.25)
\pnode(2,0){A}
\pnode(0,4){B}
\pnode(2,6){C}
\pnode(4,4){D}
\rput(1.5,3.5){\small{$A$}}
\rput(1.5,4.5){\small{$B$}}
\rput(2.5,4.5){\small{$C$}}
\rput(2.5,3.5){\small{$D$}}
\multido{\iA=0+1}{7}{\psline[linestyle=dashed,linecolor=blue](0,\iA)(4,\iA)}
\multido{\iB=0+1}{5}{\psline[linestyle=dashed,linecolor=blue](\iB,0)(\iB,6)}
\psline[linewidth=1.25pt](A)(C)
\psline[linewidth=1.25pt](B)(D)
\pspolygon[linewidth=2pt,linecolor=red](A)(B)(C)(D)
\pscurve[linewidth=1pt]{->}(2.75,4.75)(2.8,5.25)(2.65,5.75)(2,6.25)(1.25,6)(0.75,5.25)
\pscurve[linewidth=1pt]{->}(2.5,2.5)(2.95,1)(2.65,0.2)(2,-0.25)(1,0)(0.5,1.5)
\end{pspicture}

\end{document}


How do I make the curved arrows smooth?

I guess the \psbezier function is the way to do it but I cannot make it look nice, so help will be much appreciated.

Update

In case someone finds the figure useful, here is a generalization of the code:

\documentclass[a4paper]{article}

\usepackage[hmargin=2.4cm,vmargin=3cm]{geometry}
\usepackage{subcaption}
\usepackage{auto-pst-pdf,pstricks-add}
\usepackage{expl3}

\ExplSyntaxOn
\cs_new_eq:NN
\calculate
\fp_eval:n
\ExplSyntaxOff

\newcommand*{\betegn}[3]{%
\rput(!#1 4 div \figur\space mul #2 4 div \figur\space mul){\small{$#3$}}
}

\begin{document}

\begin{figure}[htbp]
% Figure number.
\def\figur{2}
% Constants.
\def\hoejde{\calculate{3*\figur}}
\def\bredde{\calculate{2*\figur}}
\def\faktorA{\calculate{\hoejde+1}}
\def\faktorB{\calculate{\bredde+1}}
\def\faktorC{\calculate{\hoejde-1}}
\def\faktorD{\calculate{\figur-1}}
\def\skalering{\calculate{2.5/\figur}}
\centering
\psset{
unit=\skalering
}
\begin{subfigure}{0.58\textwidth}
\centering
\begin{pspicture}(\bredde,\hoejde)
\pnode(!\figur\space 0){A}
\pnode(!0 \bredde\space){B}
\pnode(!\figur\space \hoejde\space){C}
\pnode(!\bredde\space \bredde\space){D}
\betegn{3}{7}{A}
\betegn{3}{9}{B}
\betegn{5}{9}{C}
\betegn{5}{7}{D}
\psset{
linestyle=dashed,
linecolor=blue
}
\multido{\iA=0+1}{\faktorA}{\psline(0,\iA)(\bredde\space,\iA)}
\multido{\iB=0+1}{\faktorB}{\psline(\iB,0)(\iB,\hoejde\space)}
\psset{
linewidth=1.25pt,
linestyle=solid,
linecolor=black
}
\psline(A)(C)
\psline(B)(D)
\pspolygon[linewidth=2pt,linecolor=red](A)(B)(C)(D)
\end{pspicture}
\subcaption{Before the rearrangement.}
\end{subfigure}
\begin{subfigure}{0.38\textwidth}
\centering
\begin{pspicture}(\figur,\hoejde)
\pnode(0,0){A}
\pnode(!0 \bredde\space){B}
\pnode(!0 \hoejde\space){C}
\pnode(!\figur\space \hoejde\space){D}
\pnode(!\figur\space \bredde\space){E}
\pnode(!\figur\space 0){F}
\betegn{3}{7}{A}
\betegn{3}{9}{B}
\betegn{1}{11}{C}
\betegn{1}{1}{D}
\psset{
linestyle=dashed,
linecolor=blue
}
\multido{\iC=1+1}{\faktorC}{\psline(0,\iC)(\figur\space,\iC)}
\multido{\iD=1+1}{\faktorD}{\psline(\iD,0)(\iD,\hoejde\space)}
\psset{
linewidth=1.25pt,
linestyle=solid,
linecolor=black
}
\pspolygon(A)(C)(D)(F)
\psline(B)(E)
\psline[linewidth=2pt,linecolor=red](F)(B)(D)
\end{pspicture}
\subcaption{After the rearrangement.}
\end{subfigure}
\caption{Figure~$\figur$.}
\end{figure}

\end{document}


All you have to do is change the value of \figur.

The document can be compiled with pdflatex -shell-escape filename.tex.

-
You can try psecurve – Marco Daniel Feb 17 '13 at 18:01
That is what I have already done but the curve is not very smooth. – Svend Tveskæg Feb 17 '13 at 18:03
use the ncurv parameter setting. – Herbert Feb 17 '13 at 18:48
@Herbert Would you mind showing me how to apply this to change the shape of the curves? I cannot see any difference when I use this, unfortunately. Is it because I have too many control points and the differences are then too small to notice? – Svend Tveskæg Feb 17 '13 at 19:09
sorry, I meant curvature. But it is better to use splines. See my answer. – Herbert Feb 17 '13 at 21:22

## 3 Answers

You can use the package \pst-bezier which gives you a nicer bezier function \psbcurve. This package also allows various modifiers that help you tweak the curve. The only problem with this approach is that arrows don't work.

\documentclass{article}

\usepackage{pstricks-add}
\usepackage{pst-bezier}

\begin{document}

\begin{pspicture}[showgrid=true](0,-0.25)(4,6.25)
\pnode(2,0){A}
\pnode(0,4){B}
\pnode(2,6){C}
\pnode(4,4){D}
\pnode(2,4){E}
\rput(1.5,3.5){\small{$A$}}
\rput(1.5,4.5){\small{$B$}}
\rput(2.5,4.5){\small{$C$}}
\rput(2.5,3.5){\small{$D$}}
% \multido{\iA=0+1}{7}{\psline[linestyle=dashed,linecolor=blue](0,\iA)(4,\iA)}
% \multido{\iB=0+1}{5}{\psline[linestyle=dashed,linecolor=blue](\iB,0)(\iB,6)}
\psline[linewidth=1.25pt](A)(C)
\psline[linewidth=1.25pt](B)(D)
\pspolygon[linewidth=2pt,linecolor=red](A)(B)(C)(D)
\pscurve[linecolor=blue,linewidth=1pt]{->}(2.75,4.75)(2.8,5.25)(2.65,5.75)(2,6.25)(1.25,6)(0.75,5.25)
\pscurve[linecolor=blue,linewidth=1pt]{->}(2.5,2.5)(2.95,1)(2.65,0.2)(2,-0.25)(1,0)(0.5,1.5)

\psset{showpoints=false,linecolor=red,linewidth=2pt,arrows=->,arrowscale=1.5}
\psbcurve(2.75,4.75)(2.5,6)(1.5,6.5)(0.75,5.25)
\psbcurve(2.5,2.5)(3,0.5)(1,0)(0.5,1.5)

\end{pspicture}

\end{document}


I've superimposed my bezier curves (red) on your curves (blue).

# Arrows

To get the arrows, you'll have to do a tad more work....

The lines passing through the end points and the first and last control interpolation will be tangent to the curve. If you can figure out the value of those interpolation points, you can create arrows by doing something like:

\ncnode[nodesepA=<value>,arrows=->]{interpolation_point}{end_point}


You'll have to create nodes to do this. If you set showpoints=true that can help with guessing where to define the node for the interpolation point. In fact, you don't really have to get the interpolation point, you just need to get a point that will match the curve formed by the last interpolation point and the end point of the curve.

After a bit of tweaking (using the show lines feature)

  \pnode(0.50,0){interpolationA}
\pnode(0.5,1.5){endpointA}
\ncline[nodesepA=4em,nodesepB=-0.1]{interpolationA}{endpointA}


Resulting in:

You can do something similar for the other side.

\documentclass{article}
\usepackage{pst-node}
\usepackage{pstricks-add}
\usepackage{pst-bezier}
\pagestyle{empty}
\begin{document}

\begin{pspicture}[showgrid=true](0,-0.25)(4,6.25)
\pnode(2,0){A}
\pnode(0,4){B}
\pnode(2,6){C}
\pnode(4,4){D}
\pnode(2,4){E}
\rput(1.5,3.5){\small{$A$}}
\rput(1.5,4.5){\small{$B$}}
\rput(2.5,4.5){\small{$C$}}
\rput(2.5,3.5){\small{$D$}}
% \multido{\iA=0+1}{7}{\psline[linestyle=dashed,linecolor=blue](0,\iA)(4,\iA)}
% \multido{\iB=0+1}{5}{\psline[linestyle=dashed,linecolor=blue](\iB,0)(\iB,6)}
\psline[linewidth=1.25pt](A)(C)
\psline[linewidth=1.25pt](B)(D)
\pspolygon[linewidth=2pt,linecolor=red](A)(B)(C)(D)
% \pscurve[linecolor=blue,linewidth=1pt]{->}(2.75,4.75)(2.8,5.25)(2.65,5.75)(2,6.25)(1.25,6)(0.75,5.25)
% \pscurve[linecolor=blue,linewidth=1pt]{->}(2.5,2.5)(2.95,1)(2.65,0.2)(2,-0.25)(1,0)(0.5,1.5)

\psset{showpoints=false,linecolor=red,linewidth=2pt,arrows=->,arrowscale=1.5}
\psbcurve(2.75,4.75)(2.5,6)(1.5,6.5)(0.75,5.25)
\psbcurve(2.5,2.5)(3,0.5)(1,0)(0.5,1.5)

\pnode(0.50,0){interpolationA}
\pnode(0.5,1.5){endpointA}
\ncline[nodesepA=4em,nodesepB=-0.1]{interpolationA}{endpointA}

%\psset{linecolor=black}
\pnode(1.15,6.5){interpolationB}
\pnode(0.75,5.25){endpointB}
\ncline[nodesepA=4em,nodesepB=-0.2]{interpolationB}{endpointB}

\end{pspicture}

\end{document}


Notice that I tweak both ends of the curve with nodesepA and nodesepB.

-
It looks like this is a good choice but I have a few problems: (1) How do I get arrows? (I can only get curves without an arrowhead at the end.) (2) The curve doesn't look nice at all if I replace \pscurve by \psbezier. I would much appreciate it if someone would show me how to draw the curved arrow. – Svend Tveskæg Feb 17 '13 at 18:17
I will accept your answer when you are done with it. – Svend Tveskæg Feb 17 '13 at 18:28
Thanks. I will try to make it work. – Svend Tveskæg Feb 17 '13 at 20:27

The only way to get a better shape is by adjusting the points. Turn on showpoints to make us easily adjust the points.

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-eucl}

\addtopsstyle{gridstyle}
{
gridcolor=blue!50,
griddots=10,
gridlabels=0pt,
}

\begin{document}
\begin{pspicture}(0,-0.25)(4,6.25)
\pstGeonode[PointName=none,PointSymbol=none]
(2,0){A}
(0,4){B}
(2,6){C}
(4,4){D}
%(2,4){E} <-- I don't know why the questioner defined this unused node.
\rput(1.5,3.5){\small{$A$}}
\rput(1.5,4.5){\small{$B$}}
\rput(2.5,4.5){\small{$C$}}
\rput(2.5,3.5){\small{$D$}}
\psgrid[style=gridstyle](0,0)(0,0)(4,6)
\psset{linewidth=1.25pt}
\psline(A)(C)
\psline(B)(D)
\pspolygon[linewidth=2pt,linecolor=red](A)(B)(C)(D)
\psset{linewidth=1pt,arrows=->,showpoints}
\pscurve(2.75,4.75)(2.8,5.25)(2.65,5.75)(2,6.25)(1.25,6)(0.75,5.25)
\pscurve(2.5,2.5)(2.95,1)(2.65,0.2)(2,-0.25)(1,0)(0.5,1.5)
\end{pspicture}
\end{document}

-
Thanks! This is a nice answer, so I would accept this if I hadn't already accepted the other one. – Svend Tveskæg Feb 17 '13 at 18:41
Note: the grid in PSTricks has no linestyle option so I hope someday this option will be available. – kiss my armpit Feb 17 '13 at 18:54
Unfortunately not. That was why I drew the grid with \multido and \psline with the appropriate options. – Svend Tveskæg Feb 17 '13 at 19:11
Using Geogebra to interactively obtain the points seems to be a good idea, doesn't it? – kiss my armpit Feb 17 '13 at 20:03
It might very well. :) I have only used GeoGebra very few times and it is a rather long time ago. P.S. I forgot to remove the node E, which I used for something at as earlier stage. – Svend Tveskæg Feb 17 '13 at 20:20

with package pst-bspline

 \psBspline[linewidth=1pt,arrows=->]{A}(2.75,4.75)(2.8,5.25)(2.65,5.75)(2,6.25)(1.25,6)(0.75,5.25)
\psBspline[linewidth=1pt,arrows=->]{B}(2.5,2.5)(2.95,1)(2.65,0.2)(2,-0.25)(1,0)(0.5,1.5)

-
This is definitely the way to do it. Thank you. – Svend Tveskæg Feb 17 '13 at 21:29