%%%============================================================================== %% Copyright 2024-present by Alceu Frigeri %% %% This work may be distributed and/or modified under the conditions of %% %% * The [LaTeX Project Public License](http://www.latex-project.org/lppl.txt), %% version 1.3c (or later), and/or %% * The [GNU Affero General Public License](https://www.gnu.org/licenses/agpl-3.0.html), %% version 3 (or later) %% %% This work has the LPPL maintenance status *maintained*. %% %% The Current Maintainer of this work is Alceu Frigeri %% %% This is version {1.3} {2025/10/29} %% %% The list of files that compose this work can be found in the README.md file at %% https://ctan.org/pkg/tikzdotncross %% %%%============================================================================== %% WARNING: These are personal packs/tests %% They might and probably will change at will as needed %% %%%============================================================================== \NeedsTeXFormat{LaTeX2e}[2022/06/01] \ProvidesExplPackage {tikzdotncross} {2025/10/29} {1.3} {Marking coordinates and crossing paths} %%%%%%% %%% %%% Just an attempt of having my packages info in a regular way %%% \Pkginfograb_set:nn {} { props} for each and all. %%% %%%%%%% \RequirePackage{pkginfograb} \pkginfograb_set:nn { tikzdotncross } { name = {tikzdotncross} , prefix = {dotncross} , date = {2025/10/29}, version = {1.3} , description = {Marking~ coordinates~ and~ crossing~ paths} } %%%%%%% %%% End of cut-n-paste %%%%%%% %%% %%% why that here? well, the token list's commands will be used outside expl3 'domain' %%% \makeatletter \keys_define:nn { tikzdotncross } { pin size .tl_set:N = \l__dotncross_pinsep_tl , pin size .value_required:n = true , pin size .initial:n = 1.2 , pin size .usage:n = general , pin ang .tl_set:N = \l__dotncross_pinang_tl , pin ang .value_required:n = true , pin ang .initial:n = 45 , pin ang .usage:n = general , pin color .tl_set:N = \l__dotncross_pincolor_tl , pin color .value_required:n = true , pin color .initial:n = blue , pin color .usage:n = general , pin length .tl_set:N = \l__dotncross_pindistance_tl , pin length .value_required:n = true , pin length .initial:n = 4 , pin length .usage:n = general , coord color .tl_set:N = \l__dotncross_coordcolor_tl , coord color .value_required:n = true , coord color .initial:n = red , coord color .usage:n = general , } \ProcessKeyOptions [ tikzdotncross ] \NewDocumentCommand{\setpindefaults}{m} { \keys_set:nn {tikzdotncross}{#1} } %%%%%%%%%%%%%%%%%%% %%%% %%%% some handy/auxiliary macros to define coordinate/node pairs (and selectively 'pin' them) %%%% based on the idea from Redaelli et al. (CircuiTiKz) %%%% %%%% differences: variable number of paramenters (see below) and it always also adds an empty node n %%%% %%%%%%%%%%%%%%%%%%% \keys_define:nn { tikzdotncross / show coords} { on .bool_set:N = \l__dotncross_showcoords_bool , on .value_forbidden:n = true , off .bool_set_inverse:N = \l__dotncross_showcoords_bool , off .value_forbidden:n = true , true .bool_set:N = \l__dotncross_showcoords_bool , true .value_forbidden:n = true , false .bool_set_inverse:N = \l__dotncross_showcoords_bool , false .value_forbidden:n = true , } \cs_new:Npn \__dotncross_hidecoords: { \cs_set_eq:NN \ncoord \__dotncross_coordnode:w \cs_set_eq:NN \dotcoord \__dotncross_dotcoordnode:w \cs_set_eq:NN \odotcoord \__dotncross_odotcoordnode:w } \cs_new:Npn \__dotncross_showcoords: { \cs_set_eq:NN \ncoord \__dotncross_coordpin:w \cs_set_eq:NN \dotcoord \__dotncross_dotcoordpin:w \cs_set_eq:NN \odotcoord \__dotncross_odotcoordpin:w } \NewDocumentCommand{\showcoords}{m} { \keys_set:nn {tikzdotncross / show coords}{#1} \bool_if:NTF \l__dotncross_showcoords_bool \__dotncross_showcoords: \__dotncross_hidecoords: } \cs_new_eq:NN \showcoordsfalse \__dotncross_hidecoords: \cs_new_eq:NN \showcoordstrue \__dotncross_showcoords: \cs_new:Npn \__dotncross_coordpin:w (#1) { \pincoord(#1,\l__dotncross_coordcolor_tl,\l__dotncross_pinang_tl) } \cs_new:Npn \__dotncross_coordnode:w (#1) { coordinate(#1) node[minimum ~ size=\l__dotncross_pinsep_tl pt,inner ~ sep=\l__dotncross_pinsep_tl pt](n#1){} } \cs_new:Npn \__dotncross_dotcoordpin:w (#1) { \dotpincoord(#1,\l__dotncross_coordcolor_tl,\l__dotncross_pinang_tl) } \cs_new:Npn \__dotncross_dotcoordnode:w (#1) { coordinate(#1) node[circle,minimum ~ size=\l__dotncross_pinsep_tl pt,inner ~ sep=\l__dotncross_pinsep_tl pt,fill](n#1){} } \cs_new:Npn \__dotncross_odotcoordpin:w (#1) { \odotpincoord(#1,\l__dotncross_coordcolor_tl,\l__dotncross_pinang_tl) } \cs_new:Npn \__dotncross_odotcoordnode:w (#1) { coordinate(#1) node[circle,minimum ~ size=\l__dotncross_pinsep_tl pt,inner ~ sep=\l__dotncross_pinsep_tl pt,fill=white,draw](n#1){} } %%%% %% %% And some TeX to have a (expandable) variable number of parameters %% \pincoord can be used as %% \pincoord(coord-name) That's case D %% \pincoord(coord-name,color) That's case C %% \pincoord(coord-name,color,angle) That's case B %% \pincoord(coord-name,color,angle,lenght) That's case A %% %%%% \cs_new:Npn \__dotncross_pincase:nn #1#2 { \__dotncross_pincase:w #1,,,,\__dotncross_pincaseA:w \__dotncross_pincaseB:w \__dotncross_pincaseC:w \__dotncross_pincaseD:w ;#2: } \cs_new:Npn \__dotncross_pincase:w #1,#2,#3,#4,#5#6#7#8#9: { #8:#1:#2:#3:#4:#9: } \cs_new:Npn \__dotncross_pincaseA:w :#1:#2:#3:#4:#5;#6: { \__dotncross_pincoord:nnnnn {#1}{#2}{#3}{#4}{#6} } \cs_new:Npn \__dotncross_pincaseB:w :#1:#2:#3:#4:#5;#6: { \__dotncross_pincoord:nnnnn {#1}{#2}{#3}{\l__dotncross_pindistance_tl}{#6} } \cs_new:Npn \__dotncross_pincaseC:w :#1:#2:#3:#4:#5;#6: { \__dotncross_pincoord:nnnnn {#1}{#2}{-\l__dotncross_pinang_tl}{\l__dotncross_pindistance_tl}{#6} } \cs_new:Npn \__dotncross_pincaseD:w :#1:#2:#3:#4:#5;#6: { \__dotncross_pincoord:nnnnn {#1}{\l__dotncross_pincolor_tl}{-\l__dotncross_pinang_tl}{\l__dotncross_pindistance_tl}{#6} } \cs_new:Npn \pincoord (#1) { \__dotncross_pincase:nn {#1}{} } \cs_new:Npn \dotpincoord (#1) { \__dotncross_pincase:nn {#1}{circle,fill,} } \cs_new:Npn \odotpincoord (#1) { \__dotncross_pincase:nn {#1}{circle,fill=white,draw,} } \cs_new:Npn \__dotncross_pincoord:nnnnn { \dotncross@@pincoord \l__dotncross_pinsep_tl } \bool_set_false:N \l__dotncross_showcoords_bool \showcoordsfalse %% %% Original/Old TeX code %% %% %%%%%%%%%%%%%%%%%%% %% %%%% %% %%%% some handy/auxiliary macros to define coordinate/node pairs (and selectively 'pin' them) %% %%%% based on the idea from Redaelli et al. (CircuiTiKz) %% %%%% %% %%%% differences: variable number of paramenters (see below) and it always also adds an empty node n %% %%%% %% %%%%%%%%%%%%%%%%%%% %%\newcommand\showcoordsfalse{\let\ncoord=\dotncross@@coordnode \let\dotcoord=\dotncross@@dotcoordnode \let\odotcoord=\dotncross@@odotcoordnode} %%\newcommand\showcoordstrue{\let\ncoord=\dotncross@@coordpin \let\dotcoord=\dotncross@@dotcoordpin \let\odotcoord=\dotncross@@odotcoordpin} %% %%\def\dotncross@@coordpin(#1){\pincoord(#1,\dotncross@@coordcolor,\dotncross@@pinang)} %%\def\dotncross@@coordnode(#1){coordinate(#1) node[minimum size=\dotncross@@pinsep pt,inner sep=\dotncross@@pinsep pt](n#1){}} %% %%\def\dotncross@@dotcoordpin(#1){\dotpincoord(#1,\dotncross@@coordcolor,\dotncross@@pinang)} %%\def\dotncross@@dotcoordnode(#1){coordinate(#1) node[circle,minimum size=\dotncross@@pinsep pt,inner sep=\dotncross@@pinsep pt,fill](n#1){}} %% %%\def\dotncross@@odotcoordpin(#1){\odotpincoord(#1,\dotncross@@coordcolor,\dotncross@@pinang)} %%\def\dotncross@@odotcoordnode(#1){coordinate(#1) node[circle,minimum size=\dotncross@@pinsep pt,inner sep=\dotncross@@pinsep pt,fill=white,draw](n#1){}} %% %% %%%% %% %% %% %% And some TeX to have a (expandable) variable number of parameters %% %% \pincoord can be used as %% %% \pincoord(coord-name) That's case D %% %% \pincoord(coord-name,color) That's case C %% %% \pincoord(coord-name,color,angle) That's case B %% %% \pincoord(coord-name,color,angle,lenght) That's case A %% %% %% %%%% %%\def\dotncross@@pincasew#1#2{\dotncross@@pincase#1,,,,\dotncross@@pincaseA\dotncross@@pincaseB\dotncross@@pincaseC\dotncross@@pincaseD;#2:} %%\def\dotncross@@pincase#1,#2,#3,#4,#5#6#7#8#9:{#8:#1:#2:#3:#4:#9:} %%\def\dotncross@@pincaseA:#1:#2:#3:#4:#5;#6:{\dotncross@@pincoord{#1}{#2}{#3}{#4}{#6}} %%\def\dotncross@@pincaseB:#1:#2:#3:#4:#5;#6:{\dotncross@@pincoord{#1}{#2}{#3}{\dotncross@@pindistance}{#6}} %%\def\dotncross@@pincaseC:#1:#2:#3:#4:#5;#6:{\dotncross@@pincoord{#1}{#2}{-\dotncross@@pinang}{\dotncross@@pindistance}{#6}} %%\def\dotncross@@pincaseD:#1:#2:#3:#4:#5;#6:{\dotncross@@pincoord{#1}{\dotncross@@pincolor}{-\dotncross@@pinang}{\dotncross@@pindistance}{#6}} % %%\def\pincoord(#1){\dotncross@@pincasew{#1}{}} %%\def\dotpincoord(#1){\dotncross@@pincasew{#1}{circle,fill,}} %%\def\odotpincoord(#1){\dotncross@@pincasew{#1}{circle,fill=white,draw,}} % %%\newcommand\dotncross@@pincoord[5]{% %% coordinate(#1) node[#5minimum size=\dotncross@@pinsep pt,inner sep=\dotncross@@pinsep pt](n#1){} %% node[circle, #2, inner sep=\dotncross@@pinsep pt, outer sep=0pt, radius=1pt, fill=#2!20!white, fill opacity=0.2, draw opacity=0.4, draw, %% pin={[#2, overlay, inner sep=0pt, outer sep=1pt, font=\tiny, pin distance=#4pt, %% pin edge={#2, overlay}]#3:#1}]{}% %%} \ExplSyntaxOff \usetikzlibrary{math,intersections} \RequirePackage{etoolbox} %% %% There is no easy and clean way %% to convert this all to expl3 (for instance underscore, under expl3 code régime, is a letter) %% spaces (pgf/tikz) and then ':' (which is an active character under tikz but a letter for expl3) %% ... and still being expandable %% %%%%%%%%%%%%%%%%%%% %%% %%% This will 'calculate' the intersection between a line (defined by the coordinates (#3) and (#4) and the path named #5 %%% at each intersection a coordinate named (#2-i) and a node (n#2-i) will be defined (i stands for a counter from 1 up to the number of crossings) %%% A macro named <#1T> will have the number of crossings found. %%% %%% At each intersection a semi-circle will be drawn. %%% %%% the first parameter #1, star, flips the semi-circle. %%% %%%%%%%%%%%%%%%%%%% \NewDocumentCommand{\pathcross}{sO{cross}mmmO{7pt}}{% \IfBooleanTF{#1}{\def\dotncross@path@@sign{-}}{\def\dotncross@path@@sign{}} \path[name path=#2 self] (#3) -- (#4); \draw[name intersections={of={#5} and {#2 self},name=#2,total=\CrossTotal,sort by={#2 self}}] \pgfextra{\csxdef{#2T}{\CrossTotal}} \foreach \aux in {1,...,\csuse{#2T}}{(#2-\aux) node[minimum size=#6-\pgflinewidth,inner sep=0pt](n#2-\aux){}}; \tikzmath{% coordinate \Ctmp; real \dtmp; int \idx; \Ctmp{from} = (#3); \Ctmp{to} = (#4); \dtmp{x} = \Ctmpx{to} - \Ctmpx{from}; \dtmp{y} = \Ctmpy{to} - \Ctmpy{from}; \dtmp{ang} = atan2(\dtmp{y},\dtmp{x}); \Ctmp{1st} = (n#2-1); \Ctmp{last} = (n#2-\csuse{#2T}); \idx{1st} = 1; \idx{last} = \csuse{#2T}; if \Ctmpx{1st} == \Ctmpx{from} then { if \Ctmpy{1st} == \Ctmpy{from} then { \idx{1st} = 2; }; }; if \Ctmpx{last} == \Ctmpx{to} then { if \Ctmpy{last} == \Ctmpy{to} then { \idx{last} = \idx{last}-1; }; }; } \ifnum\idx{last}<\idx{1st} \draw (#3) -- (#4); \else \draw[line width=1.8\pgflinewidth,white,rotate=\dtmp{ang}] \foreach \aux in {\idx{1st},...,\idx{last}}{(#2-\aux) +(-#6/2,0) arc[start angle=\dotncross@path@@sign180,end angle=0,radius=#6/2]}; \draw[rotate=\dtmp{ang},line cap=round] \foreach \aux in {\idx{1st},...,\idx{last}}{(#2-\aux) +(-#6/2,0) arc[start angle=\dotncross@path@@sign180,end angle=0,radius=#6/2]}; \gdef\dotncross@path@@tmpA{#3} \gdef\dotncross@path@@ListA{} \foreach \x in {\idx{1st},...,\idx{last}} {\xappto{\dotncross@path@@ListA}{\dotncross@path@@tmpA/n#2-\x,}\xdef\dotncross@path@@tmpA{n#2-\x}} \xappto{\dotncross@path@@ListA}{n#2-\idx{last}/#4} \foreach \xa/\xb in \dotncross@path@@ListA {\draw[line cap=round] (\xa) -- (\xb);} \fi } %%%%%%% %%%%%%% %%% %%% Remember: The ':' is a pgf/tikz active character %%% %%%%%%% %%%%%%% \newcommand\dotncross@@pincoord[6]{% coordinate(#2) node[#6minimum size=#1 pt,inner sep=#1 pt](n#2){} node[circle, #3, inner sep=#1 pt, outer sep=0pt, radius=1pt, fill=#3!20!white, fill opacity=0.2, draw opacity=0.4, draw, pin={[#3, overlay, inner sep=0pt, outer sep=1pt, font=\tiny, pin distance=#5pt, pin edge={#3, overlay}]#4:#2}]{}% }