%% tikzlibrarytikzphysics.core.code.tex
%% -----------------------------------------------------------
%% Core helpers shared by all tikzphysics modules.
%%
%% Provides:
%%   * \tikzphysics@length@keyhandler  --- unit-aware length key router
%%   * physics debug/.cd family     --- anchor and key overlays
%%   * \tikzphysics@registeranchors / \tikzphysics@registerkeys --- registries
%%     used by each shape so debug mode knows what to display
%%
%% Every shape module should \usetikzlibrary{tikzphysics.core}
%% before declaring its shapes.
%%
%% Author  : Vaibhav Blayer
%% Version : v1.0.0 (2026-08-12)
%% License : LPPL 1.3c
%% -----------------------------------------------------------

\makeatletter

%% ============================================================
%%  UNIT-AWARE LENGTH KEY HANDLER
%%
%%  Usage inside a key's .code handler:
%%    some key/.code = {\tikzphysics@length@keyhandler{/pgf/minimum width}{#1}}
%%
%%  Semantics:
%%    - If the user value carries a unit (4cm, 30mm, 2ex, 1.5in),
%%      that unit is respected.
%%    - If the user value is a bare number or a unit-free math
%%      expression (4, 2*sqrt(2), 3+1), the result is interpreted
%%      as centimetres.  This matches TikZ's typical "coordinate"
%%      convention and keeps JEE-physics dimensions readable.
%%
%%  IMPORTANT IMPLEMENTATION NOTE:
%%    Do NOT use \pgfkeysalso{#1=\pgfmathresult pt} directly.
%%    pgfkeys stores the RHS as unexpanded token sequence, so the
%%    shared \pgfmathresult macro gets overwritten by the next
%%    call — causing cross-contamination between keys
%%    (e.g. setting minimum width then minimum height would make
%%    both end up with the second value).  Instead, resolve to a
%%    fixed-point literal via \pgfmathsetlength + \the, then build
%%    the \pgfkeysalso call with \edef+\noexpand so the stored
%%    value is a constant string like "85.35826pt".
%% ============================================================

\newdimen\tikzphysics@length@tmpdim

%% Resolve a tikzphysics length into a concrete dimension.  Bare values
%% are centimetres; explicit TeX units are preserved.  All public size
%% keys are required to be strictly positive so invalid geometry fails
%% at the option that introduced it rather than much later in PGF math.
\newcommand{\tikzphysics@resolve@length}[2]{%
  \pgfmathparse{#2}%
  \ifpgfmathunitsdeclared
    \pgfmathsetlength{#1}{\pgfmathresult pt}%
  \else
    \pgfmathsetlength{#1}{\pgfmathresult cm}%
  \fi
  \ifdim#1>0pt\relax\else
    \PackageError{tikzphysics}%
      {Length `#2' must be greater than zero}%
      {Use a positive bare value (interpreted as cm) or a positive TeX dimension.}%
  \fi
}

\newcommand{\tikzphysics@length@keyhandler}[2]{%
  \tikzphysics@resolve@length{\tikzphysics@length@tmpdim}{#2}%
  \edef\tikzphysics@length@call{%
    \noexpand\pgfkeysalso{#1=\the\tikzphysics@length@tmpdim}%
  }%
  \tikzphysics@length@call
}

%% ============================================================
%%  ANCHOR AND KEY REGISTRIES
%%
%%  Each shape module registers the anchors it exposes and the
%%  keys it accepts.  Debug mode reads these registries to know
%%  what to overlay.
%% ============================================================

\newcommand{\tikzphysics@registeranchors}[2]{%
  \expandafter\gdef\csname tikzphysics@anchors@#1\endcsname{#2}%
}

\newcommand{\tikzphysics@registerkeys}[2]{%
  \expandafter\gdef\csname tikzphysics@keys@#1\endcsname{#2}%
}

%% Key-defaults registry: stores {key/default, key/default, ...}
%% for the debug overlay to display.
\newcommand{\tikzphysics@registerkeydefaults}[2]{%
  \expandafter\gdef\csname tikzphysics@keydefaults@#1\endcsname{#2}%
}

%% ============================================================
%%  NUMERIC (EDGE-PARAMETRIC) ANCHORS
%%
%%  Declares a family of anchors <edge>-0, <edge>-1, ..., <edge>-100
%%  linearly interpolating from (sx,sy) to (ex,ey).  Each anchor
%%  corresponds to "t%" of the way along the edge, measured from
%%  the start point.  Call from inside \pgfdeclareshape, once per
%%  edge.  Coordinate arguments may reference saved macros (or
%%  literal dimens) -- they are left unexpanded so they resolve at
%%  anchor-access time, while the integer t is baked into the
%%  generated csname and the computation.
%%
%%  CCW convention across tikzphysics is to start each edge at its
%%  CCW-trajectory starting point, e.g.:
%%    bottom  : bl -> br   (left to right)
%%    right   : br -> tr   (bottom to top)
%%    top     : tr -> tl   (right to left)
%%    left    : tl -> bl   (top to bottom)
%%    slope   : apex -> foot  (strict CCW on a wedge with br apex)
%%
%%  Usage:
%%    \tikzphysics@declareedgeanchors{bottom}{-\myhx}{-\myhy}{\myhx}{-\myhy}
%%
%%  Cost: 101 \anchor csnames per edge per shape.  Negligible at
%%  typeset time.
%% ============================================================

%% Worker: install one anchor at a specific t.
%%   #1 = edge name
%%   #2 = t integer (0..100)
%%   #3 = startx, #4 = starty, #5 = endx, #6 = endy
\def\tikzphysics@declareedgeanchor@one#1#2#3#4#5#6{%
  \anchor{#1-#2}{%
    \pgfmathsetlength{\pgf@x}{(#3)+((#2)/100)*((#5)-(#3))}%
    \pgfmathsetlength{\pgf@y}{(#4)+((#2)/100)*((#6)-(#4))}%
  }%
}

%% Dispatcher: loop 0..100 and call the worker for each.  The
%% integer t is baked into a partial call via \edef (so it survives
%% foreach scope pop); the four coordinate args are left
%% unexpanded so saved macros inside them resolve at anchor-access
%% time, not declaration time.
\def\tikzphysics@declareedgeanchors#1#2#3#4#5{%
  \foreach \tikzphysics@@t in {0,1,...,100} {%
    \edef\tikzphysics@@partial{%
      \noexpand\tikzphysics@declareedgeanchor@one{#1}{\tikzphysics@@t}%
    }%
    \tikzphysics@@partial{#2}{#3}{#4}{#5}%
  }%
}

%% ============================================================
%%  LOGICAL SHAPE OVERRIDE
%%
%%  Some physics* names are styles that reuse a base PGF shape
%%  (e.g. physicsblock is shape=rectangle, physicspulley is shape=circle).
%%  For debug lookup we want the *logical* name so the right
%%  anchor/key list is shown.
%%
%%  Usage inside a style:
%%    my shape/.style = {
%%      shape = rectangle,
%%      physics logical shape = my shape,
%%      ...
%%    }
%%
%%  The drawer checks \tikzphysics@logical@shape@<nodename> before
%%  falling back to \pgf@sh@ns@<nodename>.
%% ============================================================

\tikzset{
  %% We use `prefix after command' rather than `append after
  %% command' so the logical-shape recorder runs BEFORE any
  %% debug emitter that was queued via `every node/.append
  %% style' at a wider scope.  Without that ordering, the
  %% emitter would look up the shape while the override is
  %% still undefined and fall through to PGF's base shape.
  physics logical shape/.code = {%
    \pgfkeysalso{%
      prefix after command = {%
        \pgfextra{%
          \edef\tikzphysics@logical@tmpnode{\tikzlastnode}%
          \expandafter\xdef
            \csname tikzphysics@logical@shape@\tikzphysics@logical@tmpnode\endcsname{#1}%
        }%
      }%
    }%
  },
}

%% ============================================================
%%  DEBUG OVERLAY
%%
%%  Keys (all under the `physics debug/' path, cascadable from
%%  tikzpicture -> scope -> node):
%%    physics debug/anchors = true | false
%%    physics debug/keys    = true | false
%%    physics debug/all     = true | false   (shorthand for both)
%%
%%  Debug output is allowed to bleed outside the node's bounding
%%  box; this is intentional, because the feature is a coding aid
%%  and users will always disable it before final typesetting.
%%
%%  Visual style is tunable via the following keys:
%%    physics debug/anchor dot color
%%    physics debug/anchor dot radius
%%    physics debug/anchor label color
%%    physics debug/anchor label font
%%    physics debug/key label color
%%    physics debug/key label font
%% ============================================================

%% ---- tag-every-node style ----
%% Adds an `append after command' to every node parsed within the
%% current scope.  The append-after-command hook fires after the
%% node's group has popped, so \tikz@shape is no longer reliable
%% (it reverts to the scope default, usually `rectangle').  PGF,
%% however, stores the true shape under the internal csname
%% \pgf@sh@ns@<nodename> -- that mapping persists globally after
%% the node is complete, so we look the shape up from there.
\tikzset{
  physics debug/.cd,
  anchor dot color/.initial    = red,
  anchor dot radius/.initial   = 1.2pt,
  anchor label color/.initial  = red!80!black,
  anchor label font/.initial   = \tiny\ttfamily,
  key label color/.initial     = gray,
  key label font/.initial      = \tiny\ttfamily,
  %% `anchors=true' activates anchor overlay.  We do two things:
  %%   (a) append the emitter directly on the current context, so
  %%       per-node use (\node[physics debug/anchors=true] ...) works
  %%       on the node being declared; at picture/scope level the
  %%       `append after command' has no owner so it's benign.
  %%   (b) also install via `every node/.append style' so the flag
  %%       propagates to descendant nodes in a picture or scope.
  anchors/.is choice,
  anchors/true/.style  = {
    physics debug/@emit anchors,
    /utils/exec = {%
      \pgfkeysalso{%
        every node/.append style = {physics debug/@emit anchors}%
      }%
    }
  },
  anchors/false/.style = {},
  keys/.is choice,
  keys/true/.style     = {
    physics debug/@emit keys,
    /utils/exec = {%
      \pgfkeysalso{%
        every node/.append style = {physics debug/@emit keys}%
      }%
    }
  },
  keys/false/.style    = {},
  all/.style           = {/tikz/physics debug/anchors=true,
                          /tikz/physics debug/keys=true},
  %% ---- emitter styles (private) ----
  %% Capture only the node name here; resolve the shape inside the
  %% drawer from \pgf@sh@ns@<nodename>, which PGF sets globally
  %% when the node is registered.
  @emit anchors/.style = {
    append after command = {%
      \pgfextra{%
        \edef\tikzphysics@debug@thisnode{\tikzlastnode}%
        \edef\tikzphysics@debug@do@anchors{%
          \noexpand\tikzphysics@debug@drawanchors
            {\tikzphysics@debug@thisnode}%
        }%
        \tikzphysics@debug@do@anchors
      }%
    }
  },
  @emit keys/.style = {
    append after command = {%
      \pgfextra{%
        \edef\tikzphysics@debug@thisnode{\tikzlastnode}%
        \edef\tikzphysics@debug@do@keys{%
          \noexpand\tikzphysics@debug@drawkeys
            {\tikzphysics@debug@thisnode}%
        }%
        \tikzphysics@debug@do@keys
      }%
    }
  },
}

%% ---- shape resolver ----
%% Return the shape name to use for debug lookup.  Prefers
%% physics logical shape (set by physics* styles on composite shapes)
%% over pgf's raw shape name.  Result goes to \tikzphysics@debug@shape.
\newcommand{\tikzphysics@debug@resolveshape}[1]{%
  \expandafter\ifcsname tikzphysics@logical@shape@#1\endcsname
    \edef\tikzphysics@debug@shape{\csname tikzphysics@logical@shape@#1\endcsname}%
  \else
    \expandafter\ifcsname pgf@sh@ns@#1\endcsname
      \edef\tikzphysics@debug@shape{\csname pgf@sh@ns@#1\endcsname}%
    \else
      \let\tikzphysics@debug@shape\@empty
    \fi
  \fi
}

%% ---- drawer: anchors ----
%% For the named node #1, resolve its shape, then:
%%   - draw a small numbered dot at each registered anchor
%%   - place a vertical legend below the node listing all anchors
%% This avoids label overlap on the shape itself.
\newcounter{tikzphysics@debug@anchorcount}
\newcommand{\tikzphysics@debug@drawanchors}[1]{%
  \begingroup
    \tikzphysics@debug@resolveshape{#1}%
    \ifx\tikzphysics@debug@shape\@empty\else
      \expandafter\ifcsname tikzphysics@anchors@\tikzphysics@debug@shape\endcsname
        \edef\tikzphysics@debug@list{\csname tikzphysics@anchors@\tikzphysics@debug@shape\endcsname}%
        \edef\tikzphysics@debug@dotcolor{\pgfkeysvalueof{/tikz/physics debug/anchor dot color}}%
        \edef\tikzphysics@debug@dotradius{\pgfkeysvalueof{/tikz/physics debug/anchor dot radius}}%
        \edef\tikzphysics@debug@labelcolor{\pgfkeysvalueof{/tikz/physics debug/anchor label color}}%
        %% Pass 1: draw numbered dots on the shape
        \setcounter{tikzphysics@debug@anchorcount}{0}%
        \foreach \tikzphysics@debug@a in \tikzphysics@debug@list {%
          \stepcounter{tikzphysics@debug@anchorcount}%
          \fill[\tikzphysics@debug@dotcolor] (#1.\tikzphysics@debug@a)
            circle (\tikzphysics@debug@dotradius);%
          \node[\tikzphysics@debug@dotcolor,
                font=\tiny\bfseries,
                inner sep=0pt,
                anchor=south west,
                yshift=0.5pt, xshift=0.5pt]
            at (#1.\tikzphysics@debug@a)
            {\arabic{tikzphysics@debug@anchorcount}};%
        }%
        %% Pass 2: place legend below the node using a tabular.
        \setcounter{tikzphysics@debug@anchorcount}{0}%
        \gdef\tikzphysics@debug@legendrows{}%
        \foreach \tikzphysics@debug@a in \tikzphysics@debug@list {%
          \stepcounter{tikzphysics@debug@anchorcount}%
          %% Odd entries start a new row; even entries end it.
          \ifodd\value{tikzphysics@debug@anchorcount}%
            %% Add row separator before odd entries (except the first)
            \ifnum\value{tikzphysics@debug@anchorcount}>1
              \expandafter\xdef\expandafter\tikzphysics@debug@legendrows\expandafter{%
                \tikzphysics@debug@legendrows \noexpand\\
                \arabic{tikzphysics@debug@anchorcount}.\noexpand\space \tikzphysics@debug@a}%
            \else
              \expandafter\xdef\expandafter\tikzphysics@debug@legendrows\expandafter{%
                \tikzphysics@debug@legendrows
                \arabic{tikzphysics@debug@anchorcount}.\noexpand\space \tikzphysics@debug@a}%
            \fi
          \else
            \expandafter\xdef\expandafter\tikzphysics@debug@legendrows\expandafter{%
              \tikzphysics@debug@legendrows \noexpand&
              \arabic{tikzphysics@debug@anchorcount}.\noexpand\space \tikzphysics@debug@a}%
          \fi
        }%
        %% Place legend below the node
        \node[\tikzphysics@debug@labelcolor,
              font=\pgfkeysvalueof{/tikz/physics debug/anchor label font},
              anchor=north west,
              inner sep=2pt,
              fill=white,
              fill opacity=0.9,
              text opacity=1,
              draw=\tikzphysics@debug@dotcolor,
              draw opacity=0.3,
              line width=0.2pt,
              rounded corners=1pt]
          at (#1.south west)
          {\begin{tabular}{@{}l@{\quad}l@{}}
            \tikzphysics@debug@legendrows
           \end{tabular}};%
      \fi
    \fi
  \endgroup
}

%% ---- drawer: keys ----
%% For the named node #1, resolve its shape, then display the
%% accepted keys with default values in a boxed table placed
%% ABOVE the node (at north west) so it doesn't overlap the
%% anchor legend below.
\newcommand{\tikzphysics@debug@drawkeys}[1]{%
  \begingroup
    \tikzphysics@debug@resolveshape{#1}%
    \ifx\tikzphysics@debug@shape\@empty\else
      \expandafter\ifcsname tikzphysics@keydefaults@\tikzphysics@debug@shape\endcsname
        \edef\tikzphysics@debug@list{\csname tikzphysics@keydefaults@\tikzphysics@debug@shape\endcsname}%
        \edef\tikzphysics@debug@klabelcolor{\pgfkeysvalueof{/tikz/physics debug/key label color}}%
        %% Build tabular rows: key = default
        \gdef\tikzphysics@debug@keyrows{}%
        \foreach \tikzphysics@debug@kd in \tikzphysics@debug@list {%
          \expandafter\xdef\expandafter\tikzphysics@debug@keyrows\expandafter{%
            \tikzphysics@debug@keyrows
            \tikzphysics@debug@kd \noexpand\\
          }%
        }%
        %% Place keys box above the node
        \node[\tikzphysics@debug@klabelcolor,
              font=\pgfkeysvalueof{/tikz/physics debug/key label font},
              anchor=south west,
              inner sep=2pt,
              fill=white,
              fill opacity=0.9,
              text opacity=1,
              draw=\tikzphysics@debug@klabelcolor,
              draw opacity=0.3,
              line width=0.2pt,
              rounded corners=1pt]
          at (#1.north west)
          {\begin{tabular}{@{}l@{\;=\;}l@{}}
            \multicolumn{2}{@{}l@{}}{\tikzphysics@debug@shape}\\
            \noalign{\vskip1pt\hrule\vskip2pt}
            \tikzphysics@debug@keyrows
           \end{tabular}};%
      \fi
    \fi
  \endgroup
}

\makeatother
\endinput
%%
%% End of file `tikzlibrarytikzphysics.core.code.tex'.
