%% tikzlibrarytikzphysics.mechanics.code.tex
%% -----------------------------------------------------------
%% Mechanics module for tikzphysics.
%%
%% Phase 1 scope (migrated from the pre-release surface prototype):
%%   - physicsblock  : simple rectangular block style
%%   - physicspulley : circle with optional axle-dot
%%   - \physicsstringoverpulley : tangent string segments plus circular wrap
%%
%% Later phases will add springs, pulleys with grooves, and
%% inclined-plane aliases.
%%
%% Internal namespace : \tikzphysics@mech@...
%% Requires           : tikz, calc, tikzphysics.core
%%
%% Author  : Vaibhav Blayer
%% Version : v1.0.0 (2026-08-12)
%% License : LPPL 1.3c
%% -----------------------------------------------------------

\usetikzlibrary{calc}
\usetikzlibrary{tikzphysics.core}

\makeatletter

%% ============================================================
%%  INTERNAL STATE
%% ============================================================

\def\tikzphysics@mech@pulleycenterfill{2pt}
\def\tikzphysics@mech@pulleycenterfillcolor{black}
\def\tikzphysics@mech@stringstartsolution{2}
\def\tikzphysics@mech@stringendsolution{1}
\def\tikzphysics@mech@stringdelta{-(Mod(\n1-\n2,360))}

%% Optional command arguments are often split over lines. Trim only their
%% leading/trailing spaces before handing the unchanged key list to TikZ.
\ExplSyntaxOn
\cs_new_protected:Npn \tikzphysics_mech_tikzset_trim:n #1
  {
    \tl_set:Nn \l_tmpa_tl {#1}
    \tl_trim_spaces:N \l_tmpa_tl
    \exp_args:NV \tikzset \l_tmpa_tl
  }
\cs_new_eq:NN \tikzphysics@mech@tikzsettrim \tikzphysics_mech_tikzset_trim:n
\ExplSyntaxOff

%% ============================================================
%%  TIKZ KEYS (scoped, unit-aware)
%% ============================================================

\tikzset{
  %% ---- block sizing ----
  physics block width/.code  = {\tikzphysics@length@keyhandler{/pgf/minimum width}{#1}},
  physics block height/.code = {\tikzphysics@length@keyhandler{/pgf/minimum height}{#1}},
  %% ---- pulley sizing ----
  physics pulley diameter/.code = {\tikzphysics@length@keyhandler{/pgf/minimum size}{#1}},
  %% ---- pulley axle-dot ----
  physics pulley axle radius/.code = {\def\tikzphysics@mech@pulleycenterfill{#1}},
  physics pulley axle color/.code  = {\def\tikzphysics@mech@pulleycenterfillcolor{#1}},
  physics pulley axle radius       = 2pt,
  physics pulley axle color        = black,
  %% ---- tangent string construction ----
  physics string start solution/.code = {\def\tikzphysics@mech@stringstartsolution{#1}},
  physics string end solution/.code   = {\def\tikzphysics@mech@stringendsolution{#1}},
  physics string wrap/.is choice,
  physics string wrap/clockwise/.code = {\def\tikzphysics@mech@stringdelta{-(Mod(\n1-\n2,360))}},
  physics string wrap/counterclockwise/.code = {\def\tikzphysics@mech@stringdelta{Mod(\n2-\n1,360)}},
  physics string wrap/shortest/.code = {\def\tikzphysics@mech@stringdelta{Mod(\n2-\n1+180,360)-180}},
  %% Named routes for the common case in which the first endpoint lies
  %% generally to the left of the pulley and the second lies to its right.
  %% The explicit solution/wrap keys remain available for every orientation.
  physics string route/.is choice,
  physics string route/over/.style={
    physics string start solution=2,
    physics string end solution=1,
    physics string wrap=clockwise,
  },
  physics string route/under/.style={
    physics string start solution=1,
    physics string end solution=2,
    physics string wrap=counterclockwise,
  },
  physics string route/surface-right/.style={
    physics string start solution=2,
    physics string end solution=1,
    physics string wrap=clockwise,
  },
  physics string route/shortest/.style={physics string wrap=shortest},
  physics string/.style={line width=0.5pt},
}

%% ============================================================
%%  BLOCK AND PULLEY STYLES
%% ============================================================

\tikzset{
  physicsblock/.style={
    shape=rectangle,
    physics logical shape=physicsblock,
    draw=black,
    line width=0.5pt,
    fill=none,
    inner sep=0pt,
    outer sep=0pt,
    minimum width=1cm,
    minimum height=1cm,
  },
  physicspulley/.style={
    shape=circle,
    physics logical shape=physicspulley,
    draw=black,
    line width=0.5pt,
    fill=none,
    inner sep=0pt,
    outer sep=0pt,
    minimum size=1cm,
    path picture={%
      \def\tikzphysics@mech@pulley@none{none}%
      \ifx\tikzphysics@mech@pulleycenterfill\tikzphysics@mech@pulley@none\relax
      \else
        \fill[\tikzphysics@mech@pulleycenterfillcolor]
          (path picture bounding box.center)
          circle[radius=\tikzphysics@mech@pulleycenterfill];%
      \fi
    },
  },
}

%% ============================================================
%%  TANGENT STRING OVER A PULLEY
%%
%%  Usage:
%%    \physicsstringoverpulley[<TikZ options>]{<start>}{<pulley>}{<end>}
%%
%%  The start and end arguments are coordinate names without parentheses;
%%  the pulley argument is the name of a physicspulley node. The two straight
%%  portions terminate at exact tangent points computed by TikZ's calc
%%  library. Between them, the path follows the pulley's true circular arc.
%%
%%  The default surface-right route (solutions 2/1, clockwise wrap) matches a
%%  block approaching parallel to a horizontal or rising surface. The string
%%  passes over the pulley's upper rim before descending on its right. The
%%  three component keys remain available for other configurations.
%% ============================================================

\newcommand{\physicsstringoverpulley}[4][]{%
  \begin{scope}[
    physics string route=surface-right]
    \tikzphysics@mech@tikzsettrim{#1}%
    \draw[physics string]
      let
        \p1=(tangent cs:node=#3,point={(#2)},solution=\tikzphysics@mech@stringstartsolution),
        \p2=(#3.center),
        \p3=(tangent cs:node=#3,point={(#4)},solution=\tikzphysics@mech@stringendsolution),
        \n1={atan2(\y1-\y2,\x1-\x2)},
        \n2={atan2(\y3-\y2,\x3-\x2)},
        \n3={veclen(\x1-\x2,\y1-\y2)},
        \n4={\tikzphysics@mech@stringdelta}
      in
        (#2) -- (\p1)
        arc[start angle=\n1,delta angle=\n4,radius=\n3]
        -- (#4);
  \end{scope}%
}

%% ============================================================
%%  ANCHOR AND KEY REGISTRATION (for debug overlays)
%%
%%  physicsblock and physicspulley are thin styles over rectangle and
%%  circle, so we register a curated list of anchors that are
%%  most useful in mechanics diagrams.
%% ============================================================

\tikzphysics@registeranchors{physicsblock}{%
  center, north, south, east, west,
  north east, north west, south east, south west}

\tikzphysics@registeranchors{physicspulley}{%
  center, north, south, east, west,
  north east, north west, south east, south west}

\tikzphysics@registerkeys{physicsblock}{%
  physics block width, physics block height}
\tikzphysics@registerkeydefaults{physicsblock}{%
  physics block width/1cm, physics block height/1cm}

\tikzphysics@registerkeys{physicspulley}{%
  physics pulley diameter, physics pulley axle radius, physics pulley axle color}
\tikzphysics@registerkeydefaults{physicspulley}{%
  physics pulley diameter/1cm, physics pulley axle radius/2pt, physics pulley axle color/black}

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