How has it been possible to develop a huge vector graphics package, PGF/TikZ, entirely within the TeX language? Exactly how is it working under the hood? Which techniques and TeX primitives does it rely on to produce its graphical output in my TeX document?
[Tex/LaTex] How does PGF/TikZ work
tikz-pgf
Related Solutions
An example with let
and veclen
:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
\coordinate (a) at (0,0);
\coordinate (b) at (4,2);
\draw let
\p1 = (a),
\p2 = (b),
\n1 = {veclen((\x2-\x1),(\y2-\y1))}
in
(a) to[sloped,above] node{\n1} (b);
\end{tikzpicture}
\end{document}
An adaption of your original code:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\def\drawfontbox#1{%
\begin{tikzpicture}[%
MyArr/.style={|<->|,>=latex},
MyLabel/.style={font={\tiny}}]
\node[rectangle,draw,inner sep=0pt,outer sep=0pt] (X){\Huge #1};
\draw
let
\p1 = (X.base west),
\p2 = (X.south west),
\p3 = (X.south east),
\p4 = (X.north west),
\p5 = (X.north east),
\n1 = {veclen(\x5-\x4,\y5-\y4)}, % width
\n2 = {veclen(\x5-\x3,\y5-\y3)}, % height
\n3 = {veclen(\x4-\x1,\y4-\y1)}, % x-height
\n4 = {veclen(\x2-\x1,\y2-\y1)} % depth
in
([yshift=5pt] X.north west)
edge[MyArr] node [above=-1pt,MyLabel]{width = \n1}
([yshift=5pt] X.north east)
([xshift=-5pt]X.base west)
edge[MyArr] node [left,MyLabel] {x-height=\n3}
([xshift=-5pt] X.north west)
([xshift=-5pt]X.base west)
edge[-|,>=latex] node [left,MyLabel] {depth=\n4}
([xshift=-5pt] X.south west)
([xshift=5pt]X.north east)
edge[MyArr] node [right,MyLabel] {height=\n2}
([xshift=5pt] X.south east)
;
\draw[red, line width=0.4pt] (X.text) circle(1pt)[fill=red] -- (X.base east);
\end{tikzpicture}
}
\begin{document}
\drawfontbox{QWERTY}
\drawfontbox{Lorem Ipsum}
\drawfontbox{What?}
\end{document}
Drawing the node only produces the outer rectangle, but it is used to define all the internal coordinates and the contact anchor points. \drawMyamp does the internal circuitry. By tradition, the origin is aligned with all of the contact anchor points.
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{circuits.logic.US,circuits.ee.IEC,positioning,fit}
\newcommand{\UseGlobalScale}
{\pgfgettransformentries{\xscale}{\@tempa}{\@tempa}{\yscale}{\@tempa}{\@tempa}}
\let\xscale=*
\let\yscale=*
% ***************************** myamp node *********************************
% contact anchor points: left, above, out
% internal anchor points: A, B, C, D, E, F, G
\pgfdeclareshape{myamp}{
\savedmacro{\resize}{ % restore global scale factor
\if*\xscale \relax \else \pgftransformxscale{\xscale} \fi
\if*\yscale \relax \else \pgftransformyscale{\yscale} \fi
}
\anchor{center}{\pgfpointorigin} % within the node, (0,0) is the center
\anchor{text} % this is required to center text in the node (not used here)
{\pgfpoint{-.5\wd\pgfnodeparttextbox}{-.5\ht\pgfnodeparttextbox}}
\anchor{left}{\pgfpoint{-2cm}{0cm}}
\anchor{above}{\pgfpoint{0cm}{2cm}}
\anchor{out}{\pgfpoint{3cm}{0cm}}
\anchor{A}{\pgfpoint{-1.5cm}{0cm}}
\anchor{B}{\pgfpointorigin}
\anchor{C}{\pgfpoint{0cm}{1.5cm}}
\anchor{D}{\pgfpoint{1cm}{0cm}}
\anchor{E}{\pgfpoint{2.5cm}{0cm}}
\anchor{F}{\pgfpoint{1cm}{1cm}}
\anchor{G}{\pgfpoint{2.5cm}{1cm}}
\foregroundpath{ % draw border
\pgfpathrectanglecorners{\pgfpoint{-1.75cm}{-1cm}}{\pgfpoint{2.75cm}{1.75cm}}
\pgfusepath{draw}}
}
%************************ draw myamp components ****************************
% component names = #1 R1, #1 R2, #1 C1, #1 C2 and #1 opamp
\newcommand{\drawMyamp}[2]{ % #1 = node name, #2 = rotation angle
\draw
node[contact] at(#1.A){}
node[contact] at(#1.B){}
node[contact] at(#1.C){}
node[contact] at(#1.D){}
node[contact] at(#1.E){}
node[resistor,rotate=#2](#1 R1) at($(#1.A)!.5!(#1.B)$){}
node[resistor,rotate={90+#2}](#1 R2) at($(#1.B)!.5!(#1.C)$){}
node[capacitor,rotate=#2](#1 C1) at($(#1.B)!.5!(#1.D)$){}
node[capacitor,rotate=#2](#1 C2) at($(#1.F)!.5!(#1.G)$){}
node[buffer gate,rotate=#2](#1 opamp) at($(#1.D)!.5!(#1.E)$){};
\draw[thin]
(#1.left) -- (#1.A) -- (#1 R1.west)
(#1 R1.east) -- (#1.B) -- (#1 R2.west)
(#1 R2.east) -- (#1.C) -- (#1.above)
(#1.B) -- (#1 C1.west)
(#1 C1.east) -- (#1.D) -- (#1 opamp.west)
(#1.D) -- (#1.F) -- (#1 C2.west)
(#1 C2.east) -- (#1.G) -- (#1.E) -- (#1 opamp.east)
(#1.E) -- (#1.out);
}
%*************************************************************************
\begin{document}
\begin{tikzpicture}[circuit ee IEC,circuit logic US,x=3cm,y=2cm,semithick,
set resistor graphic=var resistor IEC graphic]
\UseGlobalScale % save scale factor for myamp
% Box on the left (non circuit stuff)
\draw (0,0) rectangle (2,2);
\draw (1,1) rectangle (1.8,1.8);
\draw (0.3,0.2) rectangle (0.5,0.5);
\draw (3,0) node[myamp,thick,dashed](amp1){};
\drawMyamp{amp1}{0}
\draw (3.1,2) node[myamp,color=red,rotate=90](amp2){};
\drawMyamp{amp2}{90}
\draw (amp1 R1.south) node[below]{$100 K\Omega$};
\end{tikzpicture}
\end{document}
There are two ways to add labels to the components. You could add a lot of arguments to the macro, or you can put labels in nodes at the anchor points.
Best Answer
Let's look at a simple example
The
\tracingmacros=1
instruction will show all macro expansions in the log file.Compiling with
latex
we findWith
pdflatex
we findWith
xelatex
, we seeFinally,
lualatex
(with LuaTeX v. 0.90), producesHigher level graphic commands are translated into lower level ones, but different for each engine used. PGF has various drivers and loads the relevant one, which provides the translations specially tailored for the used engine.
The primitive
\special
simply writes its argument to the DVI (or XDV) file and it's a duty ofdvips
orxdvipdfmx
to use this code for providing a graphic rendering. Withpdftex
there is\pdfliteral
that writes PDF code to the PDF file and the same forluatex
, just with a different name.Dealing with each possible graphic command would require a book. Look at the files
for more information.