% % CoDi: Commutative Diagrams for TeX % Copyright (c) 2015-2024 Paolo Brasolin % SPDX-License-Identifier: MIT % % This file is part of CoDi 1.1.2, released on 2024/04/22 under MIT license. % % μανδύας • (mandýas) % 1. cloak % 2. mantle % 3. dolman % Mandias defines the aesthetics aspect of the user level functionality, % together with some baseline configuration. \usetikzlibrary[calc] % \usetikzlibrary[decorations.pathreplacing] % \usetikzlibrary{decorations.pathmorphing} % \usetikzlibrary[decorations.markings] % \usetikzlibrary[arrows.meta] \usetikzlibrary[positioning] \pgfqkeys{/codi}{ %==[ universal styles ]========================================================= every diagram/.append style={}, every layout/.append style={ /codi/every object/.append style={shape=codi baseline centered rectangle}, square, }, every object/.append style={}, every arrow/.append style={ >=stealth, }, every label/.append style={ auto, inner sep=0.5ex, font=\everymath\expandafter{\the\everymath\scriptstyle} }, %==[ arrow styles ]============================================================= /codi/arrows/.cd, crossing over/clearance/.initial=0.5ex, crossing over/color/.initial=white, crossing over/.style={ /tikz/preaction={ -, draw=\pgfkeysvalueof{/codi/arrows/crossing over/color}, line width=\pgfkeysvalueof{/codi/arrows/crossing over/clearance}, }, }, shove/.style={ /tikz/transform canvas={ /tikz/shift={($(\tikztostart)!#1!-90:(\tikztotarget)-(\tikztostart)$)} } }, slide/.style={ /tikz/transform canvas={ /tikz/shift={($(\tikztostart)!#1!0:(\tikztotarget)-(\tikztostart)$)} } }, %==[ label styles ]============================================================= /codi/labels/.cd, mid/.style={ /tikz/fill=white, /tikz/shape=circle, /tikz/anchor=center, /tikz/inner sep=.25ex }, %=[ objects styles ]============================================================ /codi/objects/.cd, % TODO: reflect on these styles % tetragonal/.style 2 args={ % /tikz/node distance=#2 and #1 % }, % square/.style={ % /codi/objects/rectangular={#1}{#1} % }, % golden/.style={ % /codi/objects/rectangular={#1}{0.618*#1} % }, % % comb/.style={ % % /codi/objects/rectangular={#1}{sqrt(3/4)*#1}, % % }, % % comb/.default=4em, % square/.default=4em, % golden/.default=4em, %=[ lattice styles ]============================================================ /codi/layouts/.cd, hexagonal/.code args={#1side #2 angle #3}{ \pgfkeys{/codi/layouts/#1hexagonal=side {#2} angle {#3}}, }, horizontal hexagonal/.style args={side #1 angle #2}{ /codi/layouts/tetragonal=base {#1} height {tan(#2)*#1*0.5}, /tikz/every odd row/.append style={/tikz/xshift=(#1)*0.5}, }, vertical hexagonal/.style args={side #1 angle #2}{ /codi/layouts/tetragonal=base {tan(#2)*#1*0.5} height {#1}, /tikz/every odd column/.append style={/tikz/yshift=-1*(#1)*0.5}, }, hexagonal/.default=horizontal side 4.5em angle 60, % tetragonal/.style args={base #1 height #2}{ /tikz/column sep={{#1},between origins}, /tikz/row sep={{#2},between origins}, }, tetragonal/.default=base 4.5em height 2.8em, % square/.style={ /codi/layouts/tetragonal=base {#1} height {#1}, }, golden/.style={ /codi/layouts/tetragonal=base {#1} height {0.618*#1}, }, square/.default=4.5em, golden/.default=4.5em, %=[ diagram styles ]============================================================ /codi/diagrams/.cd, grid/.style 2 args={ /tikz/x={#1}, /tikz/y={#2}, /tikz/on grid, }, metric/.style 2 args={ % NOTE: {1 and 1}{1} is infty-norm, unit circle is unit square % NOTE: {2}{0.5} is 1-norm, circle of radius 2 is rhombus circumscribing base hexagon /tikz/node distance={#1}, % TODO: implement control to allow for explicit units on single factor specs /tikz/above left/.code={\tikz@lib@place@handle@{##1}{south east}{-1}{1}{north west}{#2}}, /tikz/above right/.code={\tikz@lib@place@handle@{##1}{south west}{1}{1}{north east}{#2}}, /tikz/below left/.code={\tikz@lib@place@handle@{##1}{north east}{-1}{-1}{south west}{#2}}, /tikz/below right/.code={\tikz@lib@place@handle@{##1}{north west}{1}{-1}{south east}{#2}}, }, % hexagonal/.code args={#1side #2 angle #3}{ \pgfkeys{/codi/diagrams/#1hexagonal=side #2 angle #3} }, horizontal hexagonal/.style args={side #1 angle #2}{ /codi/every layout/.append style={/codi/layouts/hexagonal=horizontal side {#1} angle {#2}}, /codi/diagrams/grid={#1*0.5}{#1*tan(#2)*0.5}, /codi/diagrams/metric={2}{0.5}, }, vertical hexagonal/.style args={side #1 angle #2}{ /codi/every layout/.append style={/codi/layouts/hexagonal=vertical side {#1} angle {#2}}, /codi/diagrams/grid={#1*tan(#2)*0.5}{#1*0.5}, /codi/diagrams/metric={2}{0.5}, }, hexagonal/.default=horizontal side 4.5em angle 60, % tetragonal/.style args={base #1 height #2}{ /codi/every layout/.append style={/codi/layouts/tetragonal=base {#1} height {#2}}, /codi/diagrams/grid={#1}{#2}, /codi/diagrams/metric={1 and 1}{1}, }, tetragonal/.default=base 4.5em height 2.8em, % square/.style={ /codi/every layout/.append style={/codi/layouts/square=#1}, /codi/diagrams/tetragonal=base {#1} height {#1}, }, golden/.style={ /codi/every layout/.append style={/codi/layouts/golden=#1}, /codi/diagrams/tetragonal=base {#1} height {0.618*#1}, }, square/.default=4.5em, golden/.default=4.5em, } %==[ baseline centered rectangle shape ]======================================== % The math formula axis height is recovered and stored as a pgf function. % NOTE: the LuaTeX version is needed just by ConTeXt \pgfutil@ifluatex \directlua{tex.enableprimitives('kD', {'Umathaxis'})} \pgfmathdeclarefunction{kD_math_formula_axis_height}{0}{% \begingroup% $\relax$% update fontdimens % See TeX by Topic §23.5 for details. \pgfmathreturn\the\kDUmathaxis\textstyle% \endgroup} \else% if using (pdf)tex \pgfmathdeclarefunction{kD_math_formula_axis_height}{0}{% \begingroup% $\relax$% update fontdimens % See TeX by Topic §23.5 for details. \pgfmathreturn\the\fontdimen22\textfont2% \endgroup} \fi \pgfqkeys{/codi/baseline centered rectangle}{ center raise/.initial=kD_math_formula_axis_height } % Then the shape is defined by inheritance. \pgfdeclareshape{codi baseline centered rectangle} { % Inherit the rectangle shape. \inheritsavedanchors[from={rectangle}] \inheritanchor[from={rectangle}]{base} \inheritanchor[from={rectangle}]{north} \inheritanchor[from={rectangle}]{south} \inheritanchor[from={rectangle}]{base west} \inheritanchor[from={rectangle}]{north west} \inheritanchor[from={rectangle}]{south west} \inheritanchor[from={rectangle}]{base east} \inheritanchor[from={rectangle}]{north east} \inheritanchor[from={rectangle}]{south east} \inheritanchor[from={rectangle}]{mid} \inheritanchor[from={rectangle}]{mid west} \inheritanchor[from={rectangle}]{mid east} \inheritbackgroundpath[from={rectangle}] % Redefine west, center and east anchors % setting their y coordinates to center raise. \anchor{center}{\pgf@anchor@rectangle@center\pgfmathsetlength\pgf@y% {\pgfkeysvalueof{/codi/baseline centered rectangle/center raise}}} \anchor{west}{\pgf@anchor@rectangle@west\pgfmathsetlength\pgf@y% {\pgfkeysvalueof{/codi/baseline centered rectangle/center raise}}} \anchor{east}{\pgf@anchor@rectangle@east\pgfmathsetlength\pgf@y% {\pgfkeysvalueof{/codi/baseline centered rectangle/center raise}}} % Save the original anchors as alternate "real" versions. \anchor{real center}{\pgf@anchor@rectangle@center} \anchor{real west}{\pgf@anchor@rectangle@west} \anchor{real east}{\pgf@anchor@rectangle@east} % Redefine the border anchor calculation. \anchorborder{% % (x,y) = target % let tempdima = center raise \pgfmathsetlength\pgfutil@tempdima% {\pgfkeysvalueof{/codi/baseline centered rectangle/center raise}}% % let b = (x,y) = target \pgf@xb=\pgf@x% \pgf@yb=\pgf@y% % let (x,y) = south west \southwest% % let a = (x,y) = south west \pgf@xa=\pgf@x% \pgf@ya=\pgf@y% % let (x,y) = north east \northeast% % let (x,y) = (x,y) - a = north east - south west = (width, height) \advance\pgf@x by-\pgf@xa% \advance\pgf@y by-\pgf@ya% % let c = (x,y)/2 = (width, height)/2 = (width/2, height/2) \pgf@xc=.5\pgf@x% \pgf@yc=.5\pgf@y% % let a = a + c = south west + (width/2, height/2) = center \advance\pgf@xa by\pgf@xc% \advance\pgf@ya by\pgf@yc% % if by = target y > 0 \ifdim\pgf@yb>0pt% % let (x,y) = north east \northeast% % let cy = y = north east y \pgf@yc=\pgf@y% % let cy = cy - center raise = north east y - center raise \advance\pgf@yc by-\pgfutil@tempdima% \else% % let (x,y) = south west \southwest% % let cy = y = - south west y \pgf@yc=-\pgf@y% % let cy = cy + center raise = - south west y + center raise \advance\pgf@yc by\pgfutil@tempdima% \fi \edef\pgf@marshal{% % calculate the intersection of the half line from the origin \noexpand\pgfpointborderrectangle % passing through target {\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}} % and the rectangle centered on the origin % whose upper right corner is % (width/2, +north east y - center raise) if target y > 0 % (width/2, -south west y + center raise) if target y < 0 {\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}% }% % let (x,y) = the intersection \pgf@process{\pgf@marshal}% % let x = x + ax = width/2 + center x \advance\pgf@x by\pgf@xa% % let y = y + tempdima = ±(ne/sw y - center raise) + center raise \advance\pgf@y by\pgfutil@tempdima% % that is, y = + north east y if target y > 0 % y = - south west y + 2 * center raise if target y < 0 % % NOTE: in essence, we're just compensating for the redefinition % of ne/sw anchors that shifted them by cr below the real center. % ┏━━━━━━┯━━━━━━┓ ╮╮ % ┃ │ ┃ ││ + ney - cr % ╭╭ ┠──────┼──────┨ ╮│╯ y > 0 % - swy + cr │╰╭ ┣━━━━━━┿━━━━━━┫ ╯╯ ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ % ╰ ╰ ┗━━━━━━┷━━━━━━┛ y < 0 }% }% %==[ prompter ]================================================================= % This key is meant for visual assistance with the node labeling automation. \pgfqkeys{/codi}{ prompter label/.style={ /tikz/.cd, inner sep=0sp, font=\ttfamily\bfseries\tiny, line width=1pt, draw=violet, fill=violet, text=white, overlay, label anchor/.style={tikz@label@post/.append style={anchor=##1}}, label anchor=north east, label position=south east }, prompter pinner/.style={ /tikz/draw=violet, /tikz/line width=1sp, /tikz/label={[/codi/prompter label]:#1}, }, prompter/.style={/bapto/output/.forward to=/codi/prompter pinner} }