Shortest way from pointers to nodes
Shortest way from pointers to nodes
Is there a way that the pointers from the callouts use the shortest possible way to the nodes? So this is somehow an optimization problem ;-)
This is my code. The callout part is copied from here.
documentclass[border=10mm]standalone
usepackagetikz
usepackage[utf8]inputenc
usepackage[T1]fontenc
usetikzlibrarypositioning,chains, shapes.geometric,decorations.pathreplacing,calc,shadows.blur,shapes
tikzset
add path/.style =
decoration=show path construction,
moveto code=
xdefsavedpathsavedpath (tikzinputsegmentfirst)
,
lineto code=
xdefsavedpathsavedpath -- (tikzinputsegmentlast)
,
curveto code=
xdefsavedpathsavedpath .. controls (tikzinputsegmentsupporta) and (tikzinputsegmentsupportb) ..(tikzinputsegmentlast)
,
closepath code=
xdefsavedpathsavedpath -- cycle
,
decorate
,
store path/.style = add path,
store path/.prefix code=xdefsavedpath,
callouts/.style=
store path,
append after command=
foreach target in #1
($(callout)!2pt!-90:target$)--target --($(callout)!2pt!90:target$)
savedpath
,
alias=callout
,
custom style/.style=fill=blue!20,text=,
begindocument
begintikzpicture[
[baserect/.style=text width=0.5cm,align=left,draw,,
diam/.style=diamond,draw,align=left,text width=1cm,inner sep=1.5pt,fill=yellow,text=white,minimum size=2cm,
basecirc/.style=circle,draw,align=center,text width=1.5cm,
circ/.style=basecirc,fill=blue!60,text=black]
node [diam] (1) asdf;
node [circ, right=5 of 1] (2) asdf;
node [diam, below=2 of 2] (3) asdf;
path[custom style] (3,1) node[callouts=(1.east),(2.west),(3.north west)]blah blah;
endtikzpicture
enddocument
Edit: My question is how I can optimize the distance from the callout to where the pointers touch the nodes. In the image the green line is shorter than the red one. How do I find the coordinate of the point of the node which is closest to the callout?
pgfpointshapeborder
blah
blah.south east
pgfpointshapeborderblue circleblah.south east
2 Answers
2
One possibility that is not a real optimization, but can be approached is to use the fit
library. This library creates a node that contains all the coordinates. This node is the smallest bounding box
that contains all the coordinates.
Once this is done, we can for example place the callout in the center of this bounding box.
fit
bounding box
documentclass[border=10mm]standalone
usepackagetikz
usepackage[utf8]inputenc
usepackage[T1]fontenc
usetikzlibrarypositioning,chains, shapes.geometric,decorations.pathreplacing,calc,shadows.blur,shapes
usetikzlibraryfit
tikzset
add path/.style =
decoration=show path construction,
moveto code=
xdefsavedpathsavedpath (tikzinputsegmentfirst)
,
lineto code=
xdefsavedpathsavedpath -- (tikzinputsegmentlast)
,
curveto code=
xdefsavedpathsavedpath .. controls (tikzinputsegmentsupporta) and (tikzinputsegmentsupportb) ..(tikzinputsegmentlast)
,
closepath code=
xdefsavedpathsavedpath -- cycle
,
decorate
,
store path/.style = add path,
store path/.prefix code=xdefsavedpath,
callouts/.style=
store path,
append after command=
foreach target in #1
($(callout)!2pt!-90:target$)--target --($(callout)!2pt!90:target$)
savedpath
,
alias=callout
,
custom style/.style=fill=blue!20,text=,
begindocument
begintikzpicture[
[baserect/.style=text width=0.5cm,align=left,draw,,
diam/.style=diamond,draw,align=left,text width=1cm,inner sep=1.5pt,fill=yellow,text=white,minimum size=2cm,
basecirc/.style=circle,draw,align=center,text width=1.5cm,
circ/.style=basecirc,fill=blue!60,text=black]
node [diam] (1) asdf;
node [circ, right=5 of 1] (2) asdf;
node [diam, below=2 of 2] (3) asdf;
node[draw=red, fit=(1) (2) (3)](fit) box;
path[custom style] (fit) node[callouts=(1.east),(2.west),(3.north west)]blah blah;
endtikzpicture
enddocument
Output:
+1.
barycentric cs:
from the pgfmanual section 13.2.2 might also be a nice option.– marmot
Sep 9 '18 at 20:24
barycentric cs:
@marmot Yes, that's exactly what I was thinking. I let you write this solution which will be more beautiful because I have to go to sleep.
– AndréC
Sep 9 '18 at 20:28
No, please add it to your nice answer. There is no point in having two "competing" answers here. ;-) I will then remove my comments.
– marmot
Sep 9 '18 at 20:31
Thanks for your answers. Apparently my question hasn't been clear enough (I'm sorry, I find it quite difficult to describe it). I hope it's clear now what I am after.
– ESV
Sep 9 '18 at 20:56
This is only a temporary post till AndréC wakes up. You can do that rather easily using the fact that you already load the calc
library, but this code redefines the syntax, i.e. you can no longer put brackets around the pointers.
calc
documentclass[border=10mm]standalone
usepackagetikz
usepackage[utf8]inputenc
usepackage[T1]fontenc
usetikzlibrarypositioning,chains, shapes.geometric,decorations.pathreplacing,calc,shadows.blur,shapes
tikzset
add path/.style =
decoration=show path construction,
moveto code=
xdefsavedpathsavedpath (tikzinputsegmentfirst)
,
lineto code=
xdefsavedpathsavedpath -- (tikzinputsegmentlast)
,
curveto code=
xdefsavedpathsavedpath .. controls (tikzinputsegmentsupporta) and (tikzinputsegmentsupportb) ..(tikzinputsegmentlast)
,
closepath code=
xdefsavedpathsavedpath -- cycle
,
decorate
,
store path/.style = add path,
store path/.prefix code=xdefsavedpath,
callouts/.style=
store path,
append after command=
foreach target in #1
let p1=($(target.center)-(callout)$),n1=atan2(y1,x1)+180
in
($(callout)!2pt!-90:(target.center)$)--(target.n1) --
($(callout)!2pt!90:(target.center)$)
savedpath
,
alias=callout
,
custom style/.style=fill=blue!20,text=,
begindocument
begintikzpicture[
[baserect/.style=text width=0.5cm,align=left,draw,,
diam/.style=diamond,draw,align=left,text width=1cm,inner sep=1.5pt,fill=yellow,text=white,minimum size=2cm,
basecirc/.style=circle,draw,align=center,text width=1.5cm,
circ/.style=basecirc,fill=blue!60,text=black]
node [diam] (1) asdf;
node [circ, right=5 of 1] (2) asdf;
node [diam, below=2 of 2] (3) asdf;
path[custom style] (3,1) node[callouts=1,2,3]blah blah;
endtikzpicture
enddocument
Thanks marmot! I would like to use for one callout normal coordinates. If I just replace the name of the nodes by coordinates it doesn't work. What do I have to do so I can use normal coordinates aswell?
– ESV
Sep 10 '18 at 18:20
@ESV In this version, you could just give the coordinates names with
coordinate (X) at ...
. I am actually hoping that Symbol 1 spells out an answer using pgfpointshapeborder
. This is the correct way to go. That's why this is only a temporary answer, and I do not want to "steal" the answer from Symbol 1 and/or AndréC.– marmot
Sep 10 '18 at 18:29
coordinate (X) at ...
pgfpointshapeborder
@marmot Feel free to answer this question, I don't know enough about the
system layer
to answer this problem.– AndréC
Sep 10 '18 at 18:45
system layer
@AndréC & marmot Thank you both for your answers. The trick with the coordinates works fine for the moment. When I have more time I'll read the respective chapter in the manual and see if I understand it. Otherwise I'll just ask again ;-)
– ESV
Sep 10 '18 at 18:47
Thanks for contributing an answer to TeX - LaTeX Stack Exchange!
But avoid …
To learn more, see our tips on writing great answers.
Required, but never shown
Required, but never shown
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
pgfpointshapeborder
might solve part of your question. For instance the shortest path fromblah
to the blue circle is fromblah.south east
topgfpointshapeborderblue circleblah.south east
. For shortest paths between rectangles, they are usually from corner to corner.– Symbol 1
Sep 9 '18 at 20:11