summaryrefslogtreecommitdiff
path: root/graphics/pgf/contrib/commutative-diagrams/tikzlibrarycommutative-diagrams.mandyas.code.tex
blob: 5f12bc2e9ae0beb206fafc4a733a7efe16e17a26 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
%
% CoDi: Commutative Diagrams for TeX
% Copyright (c) 2015-2024 Paolo Brasolin <paolo.brasolin@gmail.com>
% 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}
}