Enveloping a set of draw paths located relative to a node into a TikZ object efficiently - latex

Consider a set of draw paths located relative to a node anchor to be reused again and again in the scope of a tikzpicture. Is it possible to envolope the object creation into a macro while passing a node, a node anchor, or the anchor's coordinate as arguments? The code follows below,
\usetikzlibrary{positioning}
\usepackage{tikz}
\begin{tikzpicture}
%General positions
\def\mtHeight{2};
\def\nodexpas{0.7};
\def\seriallength{2};
%Node style
\tikzstyle{naked}=[every node/.style={inner sep=0,outer sep=0,minimum height=0,minimum width=0,node contents={}}];
%Reference nodes
\begin{scope}[every node/.style={draw,double,rounded corners, align = center,fill=white}]
%Next Element node
\node (NE) [anchor=west,outer sep=0] at (\seriallength+\nodexpas,\mtHeight) {\small Next \\ \small Element()};
%Local Stiffness node
\node (LS) [right=\nodexpas of NE.east] {\small Local \\ \small Stiffness};
%Buffer filling node
\node (BF) [right=\nodexpas of LS.east] {\small Buffer \\ \small filling};
\end{scope}
%Object "lock" data;
\def\lockdim{0.35};
\def\lockpasy{\lockdim/2};
\def\arccorneroffset{\lockdim/10};
\def\lockpasx{\lockdim/2-\arccorneroffset};
\def\arcverticaloffset{\lockdim/3};
\def\lockrelcenter{\lockdim/2+\arcverticaloffset/2+\lockpasx/2};
%First lock
\node[naked] (lock1pos) [left=\nodexpas/2 of NE.west,shape=coordinate,node contents={}];
\draw[fill = gray!50!white] (lock1pos) ++(-\lockdim/2,-\lockdim) rectangle +(\lockdim,\lockdim);
\draw (lock1pos) ++(\lockpasx,0) -- +(0,\arcverticaloffset) arc[start angle = 0, end angle = 180, radius = \lockpasx] -- +(0,-\arcverticaloffset);
%Second Lock
\node[naked] (lock2pos) [left=\nodexpas/2 of LS.west,shape=coordinate,node contents={}];
\draw[fill = gray!50!white] (lock2pos) ++(-\lockdim/2,-\lockdim) rectangle +(\lockdim,\lockdim);
\draw (lock2pos) ++(\lockpasx,0) -- +(0,\arcverticaloffset) arc[start angle = 0, end angle = 180, radius = \lockpasx];
%Third Lock
\node[naked] (lock3pos) [left=\nodexpas/2 of BF.west,shape=coordinate,node contents={}];
\draw[fill = gray!50!white] (lock3pos) ++(-\lockdim/2,-\lockdim) rectangle +(\lockdim,\lockdim);
\draw (lock3pos) ++(\lockpasx,0) -- +(0,\arcverticaloffset) arc[start angle = 0, end angle = 180, radius = \lockpasx] -- +(0,-\arcverticaloffset);
\end{tikzpicture}
Note that lock 1 and 3 are identical, but lock 2 should have one less line. Hence, is it possible to,
Define this "lock" creation macro with a toggleble boolean for the close (lock 1 and 3) and close(lock 2) variations?
Define two objects, one for an open and other for the closed locks?
If macro turns out to not be the best solution, is there another way of automatizing this procedure via, preferably, TikZ or another extension?
I'm trying to make this work using tikzset command, but without much progress. I can't figure a way to pass the node as an argument or to extract the coordinate of a node's anchor. I've checked pgf tools out, but, if possible, I'd rather solve this using only TikZ. In case TikZ alone lacks sufficient tools, pgf tools or another extension should work fine.

Related

Create new variable each time an environment in LaTeX is called

I've created an example environment for my maths notes. It takes the title of the example as the input and draws some lines with tikz. However, to do so, it requires the length of the title.
This is relatively easy to do when the environment is only called once by using \newlength{\lengthname} followed by \settowidth{\lengthname}{[length]}. However, as soon as it is called more than once, a different length must be defined. My (admittedly poor) work-around has been to pass the name of a different length, #2, every time I use my example environment.
How can I create a unique \newlength{\unique} each time I use my environment, or, is there some better way of achieving my goal?
\newenvironment{example}[2] % Example Environment
{\refstepcounter{example}
\newlength{#2}
\settowidth{#2}{\small \textbf{Example \thesection.\theexample} --- #1}
\bigskip\begin{tikzpicture}
\draw (-0.5\columnwidth,-0.2)--(-0.5\columnwidth,0)--(0.5\columnwidth,0)--(0.5\columnwidth,-0.2);
\fill[white] (-0.5#2-5pt,-1pt) rectangle (0.5#2+5pt,1pt);
\tikzlabel{0}{-0.4}{\text{\small \textbf{Example \thesection.\theexample} --- #1}}
\end{tikzpicture}}
%
{\begin{tikzpicture}
\draw (-0.5\columnwidth,0.2) -- (-0.5\columnwidth,0) -- (0.5\columnwidth,0) -- (0.5\columnwidth,0.2);
\end{tikzpicture}}
Many thanks.
My suggestion would be to use tcolorbox instead of drawing the frame yourself, but if you must use tikz, simply use a white background for your title.
Please note that your code would produce a lot of overfull box warnings. You have to consider the indention and drawing a frame of column won't fit because you need an additional two times the half the width of the tikz lines. I simply reduced the width to .49\columnwidth, but you could also take into account the width of the line in your calculation.
Also pay attention to the spacing around the ---. If you don't prevent the macro before from swallowing the space, it won't be centred.
\documentclass{article}
\usepackage{tikz}
\newcounter{example}
\newenvironment{example}[1]{%
\refstepcounter{example}%
\bigskip
\noindent%
\begin{tikzpicture}
\draw (-0.49\columnwidth,-0.2)--(-0.49\columnwidth,0)--(0.49\columnwidth,0)--(0.49\columnwidth,-0.2);
\node[fill=white,font=\small\bfseries] at (0,-1pt) {Example \thesection.\theexample{} --- #1};
\end{tikzpicture}%
\par%
}{%
\par%
\noindent%
\begin{tikzpicture}
\draw (-0.49\columnwidth,0.2) -- (-0.49\columnwidth,0) -- (0.49\columnwidth,0) -- (0.49\columnwidth,0.2);
\end{tikzpicture}%
\par%
}
\begin{document}
\begin{example}{test}
content...
\end{example}
\end{document}

How to create a mindmap in Latex with hexagonal shapes?

I'm busting my head on creating a mindmap in LaTex/TikZ with nodes being displayed not as boxes, circles or ellipses. Is there a way to create a mindmap using hexagons as children? The children ought to be connected to the corners. Parents and children should contain a short text
I've tried using the shapes package.
Thank you in advance,
Pjotr
Altering the shapes of the child nodes is easy, you could simply use regular polygon, regular polygon sides=6 from the shapes library. However altering the connections between the root node and the hexagones is more difficult (at least for us mere mortals, tikz wizards can do it, see https://tex.stackexchange.com/a/514772/36296).
Instead you could emulate a mindmap with normal nodes:
\documentclass[margin=0.3cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes}
\begin{document}
\begin{tikzpicture}
\def\nchilds{5}
\node[fill=blue,text=white,circle,minimum size=3cm] at (0,0) (root) {Root};
\foreach \x [count=\xi] in {test1, test2, test3, test4, test5}{
\shade[left color=red,right color=blue,shading angle={(360/\nchilds*\xi)-90}]
({(360/\nchilds*\xi)+3}:3.2cm) to [in=160,out=10,relative]
({(360/\nchilds*\xi)+10}:1.45cm) -- ({(360/\nchilds*\xi)-10}:1.45cm) to [in=170,out=20,relative] ({(360/\nchilds*\xi)-3}:3.2cm);
\node[regular polygon, regular polygon sides=6,fill=red,minimum width=2cm,shape border uses incircle,shape border rotate=(360/\nchilds*\xi)] at (360/\nchilds*\xi:4cm) {\x};
}
\end{tikzpicture}
\end{document}
(many thanks to #marmot for the hint about shape border rotate!)

Improving outputs in tikz package

$F_1(g)=\left\{
\begin{tikzpicture}
\node[shape=circle,draw=black] (A) {$b^1_0$};
\end{tikzpicture} \right\}$
Doing this code, I have an output like this Output
And I'd like something more centered into the brackets, like if I'm still writing instead of drawing.
You have to change the baseline of the picture to be at its center, then align that baseline to the vertical center of the text. This can be done with the option [baseline={([yshift=-.8ex]current bounding box.center)}]. I added it to the example code you gave, and also changed the inner sep of the circle to 0pt. Let me know if that works for you.
$F_1(g)=\left\{
\begin{tikzpicture}[baseline={([yshift=-.8ex]current bounding box.center)}]
\node[shape=circle,draw=black, inner sep=0pt] (A) {$b^1_0$};
\end{tikzpicture} \right\}$
\end{document}

tikz explain/annotate equation in LaTeX using straight arrows with right angles

Thanks to this excellent answer, I can get an equation as in this figure: with bent arrows. But what I really want is as in this figure: with right-angled arrows.
To simply write the code, you may start by modifying the code from here.
Update: I've turned equation annotation into a LaTeX annotate-equations package (also on CTAN), which you might find useful.
Adapting Mike Renfro's answer
to straight edges is fairly straightforward: all I did was change from
\begin{tikzpicture}[overlay]
\path[->]<1-> (nCPP) edge [bend left] (tCPP);
\path[->]<2-> (nL) edge [bend left] (tL);
\path[->]<3-> (nPPP) edge [out=0, in=0] (tPPP);
\path[->]<4-> (nPP) edge [out=0, in=-90] (tPP);
\end{tikzpicture}
to
\begin{tikzpicture}[overlay,->]
\draw<1-> (nCPP) -| (tCPP);
\draw<2-> (nL) -| (tL);
\draw<3-> (nPPP) -| (tPPP);
\draw<4-> (nPP) -| (tPP);
\end{tikzpicture}
Changes explained:
replaced the edge and bend options with -| (there's also |- to bend at right angles the other way)
replaced \path with \draw to get the lines actually drawn
moved [->] into the tikzpicture environment options because for some reason it didn't work as \draw[->].
I've also set aspectratio=169 so there's enough space for the arrow for Predictor Prior Probability (it's also possible to work around that, but more hacky). This is what it looks like:

Improving a Tikz Diagram

I have just finished my first diagram in Tikz. It looks as I wanted it to, but am unhappy with how I have 'coded' it:
\begin{tikzpicture}
[node distance=14mm,
item/.style={rounded corners,rectangle,
thick,
minimum width=20mm, minimum height=10mm}]
\node[item,draw=blue!50,fill=blue!20] (stack) {1394 Stack};
\node[item,left=of stack,draw=green!50,fill=green!20,yshift=-9mm] (app1) {Application};
\node[item,left=of stack,draw=green!50,fill=green!20,yshift=9mm] (app2) {Application};
\node[item,right=of stack,draw=orange!50,fill=orange!20] (ohci) {OHCI};
\node[item,right=of ohci,yshift=-15mm,draw=yellow!70,fill=yellow!35] (dev1) {Device};
\node[item,right=of ohci,yshift=0mm,draw=yellow!70,fill=yellow!35] (dev2) {Device};
\node[item,right=of ohci,yshift=15mm,draw=yellow!70,fill=yellow!35] (dev3) {Device};
\draw[thick] (app1) -- (stack)
(app2) -- (stack)
(stack) -- (ohci)
(ohci) -- (dev1)
(ohci) -- (dev2)
(ohci) -- (dev3);
\node[xshift=7mm,yshift=1mm] (topUser) at (app1.east |- dev3.north) {};
\node[xshift=7mm,yshift=-1mm,label=above left:User space] (botUser) at (app1.east |- dev1.south) {};
\draw[dashed] (topUser) -- (botUser);
\node[xshift=7mm,yshift=1mm] (topKern) at (stack.east |- dev3.north) {};
\node[xshift=7mm,yshift=-1mm,label=above left:Kernel space,
label=above right:Hardware\phantom{p}] (botKern) at (stack.east |- dev1.south) {};
\draw[dashed] (topKern) -- (botKern);
\end{tikzpicture}
The things which I am uncomfortable with are:
How I have manually moved the "Application" and "Device" nodes using yshift to space them apart from one another; I am sure that there must be a more elegant way of producing a simple tree-like structure
The lines (topKern -- botKern and topUser -- botUser) going from the top of the picture to the bottom; these are manually aligned on the x-axis to be between two nodes using xshift=7mm.
My use of \phantom{p} to ensure the label "Hardware" has the same baseline as the other two labels.
To build a tree structure, consult pgfmanual.pdf, Making Trees Grow.
For the lines, I would create nodes representing in the middle of two nodes, and then use the perpendicular coordinate system as you did. Also you can use current bounding box to identify the "border".
To align baselines correctly, specify text height and text depth. In your case, for instance in the style every label. But as you see, I did the labels as nodes below...
\begin{tikzpicture}[level distance=35mm,node distance=15mm,text height=1.5ex,text depth=0.25ex]
\begin{scope}[every node/.style={rounded corners,rectangle,thick,minimum width=20mm, minimum height=10mm}]
\begin{scope}[level 1/.style={sibling distance=19mm,nodes={fill=green!20,draw=green!50}}]
\node[draw=blue!50,fill=blue!20] (stack) {1394 Stack} [grow=left]
child {node (app2) {Application}}
child {node (app1) {Application}};
\end{scope}
\begin{scope}[level 1/.style={sibling distance=15mm,nodes={fill=yellow!70,draw=yellow!35}}]
\node[right= of stack,draw=orange!50,fill=orange!20] (ohci) {OHCI} [grow=right]
child {node {Device}}
child {node {Device}}
child {node {Device}};
\end{scope}
\end{scope}
\node[below=0mm of app1] (userspace) {User space};
\node at (userspace -| stack) (kernel) {Kernel};
\node at (userspace -| ohci) (hardware) {Hardware};
\path (app1) -- (stack) node[coordinate,midway] (between1) {};
\draw (ohci) -- (stack) node[coordinate,midway] (between2) {};
\draw[dashed] (current bounding box.north -| between1) -- (current bounding box.south -| between1);
\draw[dashed] (current bounding box.north -| between2) -- (current bounding box.south -| between2);
\end{tikzpicture}

Resources