%%%============================================================================== %% 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.2} {2024/10/22} %% %% 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} {2024/10/22} {1.2} {Marking coordinates and crossing paths} %%%%%%% %%% %%% Just an attempt of having my packages info in a regular way %%% Idea being: { / pkg info } for each and all. %%% %%%%%%% \keys_define:nn { tikzdotncross / pkg info} { name .code:n = {tikzdotncross} , prefix .code:n = {tikzdotncross} , date .code:n = {2024/10/22}, version .code:n = {1.2} , description .code:n = {Marking~ coordinates~ and~ crossing~ paths} } \cs_if_exist:NF \PkgInfo { \NewDocumentCommand \PkgInfo {mm} { \keys_set:nn {#1 / pkg info}{#2} } \NewDocumentCommand \PkgDescription {m} { \noindent Package~ \textbf{\PkgInfo{#1}{name}}~Version:~\PkgInfo{#1}{version}~ -~ \PkgInfo{#1}{date}\par \emph{\PkgInfo{#1}{description}}~\par } } %%%%%%% %%% 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 = \dotncross@@pinsep , pin size .value_required:n = true , pin size .initial:n = 1.2 , pin size .usage:n = general , pin ang .tl_set:N = \dotncross@@pinang , pin ang .value_required:n = true , pin ang .initial:n = 45 , pin ang .usage:n = general , pin color .tl_set:N = \dotncross@@pincolor , pin color .value_required:n = true , pin color .initial:n = blue , pin color .usage:n = general , pin length .tl_set:N = \dotncross@@pindistance , pin length .value_required:n = true , pin length .initial:n = 4 , pin length .usage:n = general , coord color .tl_set:N = \dotncross@@coordcolor , 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} } \ExplSyntaxOff %\makeatletter \usetikzlibrary{intersections} %% %% There is no easy and clean way %% to convert this all to expl3 (for instance underscore, under expl3 code regimè, 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@@sign{-}}{\def\dotncross@@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@@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@@sign180,end angle=0,radius=#6/2]}; \gdef\dotncross@@tmpA{#3} \gdef\dotncross@@ListA{} \foreach \x in {\idx{1st},...,\idx{last}} {\xappto{\dotncross@@ListA}{\dotncross@@tmpA/n#2-\x,}\xdef\dotncross@@tmpA{n#2-\x}} \xappto{\dotncross@@ListA}{n#2-\idx{last}/#4} \foreach \xa/\xb in \dotncross@@ListA {\draw[line cap=round] (\xa) -- (\xb);} \fi } %%%%%%%%%%%%%%%%%%% %%%% %%%% 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}]{}% } \showcoordsfalse