\input regression-test.tex
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{tikzphysics}

\newdimen\tikzphysicstestx
\newdimen\tikzphysicstesty
\newdimen\tikzphysicstestxx
\newdimen\tikzphysicstestyy
\newdimen\tikzphysicstestdiff
\newdimen\tikzphysicstestexpected

\newcommand{\tikzphysicsgetpoint}[2]{%
  \pgfextractx{\tikzphysicstestx}{\pgfpointanchor{#1}{#2}}%
  \pgfextracty{\tikzphysicstesty}{\pgfpointanchor{#1}{#2}}%
}

\newcommand{\tikzphysicsassertdim}[3]{%
  \tikzphysicstestexpected=#2\relax
  \tikzphysicstestdiff=#1\relax
  \advance\tikzphysicstestdiff by -\tikzphysicstestexpected\relax
  \ifdim\tikzphysicstestdiff<0pt \tikzphysicstestdiff=-\tikzphysicstestdiff\fi
  \ifdim\tikzphysicstestdiff<0.02pt
    \TYPE{PASS: #3}%
  \else
    \TYPE{FAIL: #3 (got \the#1, expected \the\tikzphysicstestexpected)}%
  \fi
}

\newcommand{\tikzphysicsassertpoint}[5]{%
  \tikzphysicsgetpoint{#1}{#2}%
  \tikzphysicstestxx=\tikzphysicstestx
  \tikzphysicstestyy=\tikzphysicstesty
  \tikzphysicsgetpoint{#3}{#4}%
  \tikzphysicsassertdim{\tikzphysicstestxx}{\tikzphysicstestx}{#5 x}%
  \tikzphysicsassertdim{\tikzphysicstestyy}{\tikzphysicstesty}{#5 y}%
}

\begin{document}
\START

\begin{tikzpicture}
  \node[physicsplatform-left, physics platform width=5, physics platform depth=2,
        physics wall angle=-90, anchor=floor-tl] (Ldown) at (0,0) {};
  \node[physicsplatform-left, physics platform width=5, physics platform depth=2,
        physics wall angle=45, anchor=floor-tl] (Lup) at (0,0) {};
  \node[physicsplatform-right, physics platform width=5, physics platform depth=2,
        physics wall angle=-90, anchor=floor-tr] (Rdown) at (0,0) {};
  \node[physicsplatform-left, physics platform width=5, physics platform depth=2,
        physics strip width=0.3, physics wall angle=135, anchor=floor-tl]
        (Lmiter) at (0,0) {};
  \node[physicsplatform-right, physics platform width=5, physics platform depth=2,
        physics strip width=0.3, physics wall angle=45, anchor=floor-tr]
        (Rmiter) at (0,0) {};

  \tikzphysicsassertpoint{Ldown}{corner}{Ldown}{floor-tl}{left corner at -90 degrees}
  \tikzphysicsassertpoint{Lup}{corner}{Lup}{floor-tl}{left corner at 45 degrees}
  \tikzphysicsassertpoint{Rdown}{corner}{Rdown}{floor-tr}{right corner at -90 degrees}

  \tikzphysicsassertpoint{Ldown}{wall-A}{Ldown}{floor-tl}{default left wall A equals floor top-left}
  \tikzphysicsassertpoint{Lup}{wall-A}{Lup}{floor-tl}{bent left wall stays continuous at corner}
  \tikzphysicsgetpoint{Ldown}{wall-D}
  \tikzphysicsassertdim{\tikzphysicstestx}{0pt}{default left wall D x}
  \tikzphysicsassertdim{\tikzphysicstesty}{-2cm}{default left wall spans platform depth}

  \tikzphysicsgetpoint{Lmiter}{wall-B}
  \tikzphysicsassertdim{\tikzphysicstestx}{-0.124264cm}{left wall B is exact 135-degree miter}
  \tikzphysicsassertdim{\tikzphysicstesty}{-0.3cm}{left miter meets floor inner edge}
  \tikzphysicsgetpoint{Rmiter}{wall-B}
  \tikzphysicsassertdim{\tikzphysicstestx}{0.124264cm}{right wall B is exact 45-degree miter}
  \tikzphysicsassertdim{\tikzphysicstesty}{-0.3cm}{right miter meets floor inner edge}

  \tikzphysicsassertpoint{Ldown}{floor-top-0}{Ldown}{floor-tr}{floor-top-0 endpoint}
  \tikzphysicsassertpoint{Ldown}{floor-top-100}{Ldown}{floor-tl}{floor-top-100 endpoint}
  \tikzphysicsassertpoint{Lup}{wall-outer-0}{Lup}{wall-A}{wall-outer-0 endpoint}
  \tikzphysicsassertpoint{Lup}{wall-outer-100}{Lup}{wall-D}{wall-outer-100 endpoint}
\end{tikzpicture}

\begin{tikzpicture}
  \node[physicswedge, physics wedge width=4, physics wedge angle=30, anchor=bl] (W) at (0,0) {};
  \tikzphysicsassertpoint{W}{base-0}{W}{bl}{wedge base-0 endpoint}
  \tikzphysicsassertpoint{W}{base-100}{W}{br}{wedge base-100 endpoint}
  \tikzphysicsassertpoint{W}{slope-0}{W}{top}{wedge slope-0 endpoint}
  \tikzphysicsassertpoint{W}{slope-100}{W}{bl}{wedge slope-100 endpoint}
\end{tikzpicture}

\begin{tikzpicture}
  \node[ramp, minimum width=8.6cm, ramp run=2.6cm, ramp rise=1.5cm]
    (Ramp) at (0,0) {};
  \tikzphysicsassertpoint{Ramp}{surface-0}{Ramp}{surface-start}
    {straight ramp surface-0 endpoint}
  \tikzphysicsassertpoint{Ramp}{surface-100}{Ramp}{surface-end}
    {straight ramp surface-100 endpoint}
  \tikzphysicsassertpoint{Ramp}{50}{Ramp}{surface-50}
    {straight ramp shorthand 50 uses contact surface}
  \tikzphysicsgetpoint{Ramp}{floor-end}
  \tikzphysicsassertdim{\tikzphysicstestx}{6cm}{straight ramp flat length}
  \tikzphysicsassertdim{\tikzphysicstesty}{0pt}{straight ramp floor is horizontal}
  \tikzphysicsgetpoint{Ramp}{ramp-top}
  \tikzphysicsassertdim{\tikzphysicstestx}{8.6cm}{straight ramp overall width}
  \tikzphysicsassertdim{\tikzphysicstesty}{1.5cm}{straight ramp explicit rise}
  \tikzphysicsgetpoint{Ramp}{normal-0}
  \tikzphysicsassertdim{\tikzphysicstestx}{0pt}{straight ramp start normal x}
  \tikzphysicsassertdim{\tikzphysicstesty}{0.5cm}{straight ramp start normal y}
  \physicsrampangle{Ramp}{$30^\circ$}
  \TYPE{PASS: straight ramp angle marker compiles}

  \node[ramp-left, minimum width=8.6cm, ramp run=2.6cm, ramp rise=1.5cm]
    (RampLeft) at (0,-2) {};
  \tikzphysicsgetpoint{RampLeft}{surface-end}
  \tikzphysicsassertdim{\tikzphysicstestx}{-8.6cm}{left straight ramp mirrors x}
  \tikzphysicsassertdim{\tikzphysicstesty}{-0.5cm}{left straight ramp retains rise}
\end{tikzpicture}

\begin{tikzpicture}
  \node[curved-ramp, curved ramp floor length=2cm,
        curved ramp radius=4cm, curved ramp angle=90,
        curved ramp back extension=1cm] (Curve) at (0,0) {};
  \tikzphysicsassertpoint{Curve}{surface-0}{Curve}{surface-start}
    {curved ramp surface-0 endpoint}
  \tikzphysicsassertpoint{Curve}{surface-100}{Curve}{surface-end}
    {curved ramp surface-100 endpoint}
  \tikzphysicsassertpoint{Curve}{80}{Curve}{surface-80}
    {curved ramp shorthand 80 uses contact surface}
  \tikzphysicsgetpoint{Curve}{surface-end}
  \tikzphysicsassertdim{\tikzphysicstestx}{6cm}{quarter-circle ramp end x}
  \tikzphysicsassertdim{\tikzphysicstesty}{4cm}{quarter-circle ramp end y}
  \tikzphysicsgetpoint{Curve}{surface-start}
  \tikzphysicsassertdim{\tikzphysicstestx}{0cm}{curved ramp floor starts at node position}
  \tikzphysicsassertdim{\tikzphysicstesty}{0pt}{curved ramp floor remains horizontal}
  \tikzphysicstestxx=\tikzphysicstestx
  \tikzphysicsgetpoint{Curve}{curve-start}
  \advance\tikzphysicstestx by -\tikzphysicstestxx
  \tikzphysicsassertdim{\tikzphysicstestx}{2cm}{curved ramp floor length}
  \tikzphysicsassertpoint{Curve}{floor-end}{Curve}{curve-start}
    {curved ramp floor meets circular arc continuously}
  \tikzphysicsgetpoint{Curve}{curve-50}
  \tikzphysicsassertdim{\tikzphysicstestx}{4.828427cm}{curved ramp arc midpoint x}
  \tikzphysicsassertdim{\tikzphysicstesty}{1.171573cm}{curved ramp arc midpoint y}
  \tikzphysicsassertpoint{Curve}{curve-0}{Curve}{curve-start}
    {curved ramp curve-0 endpoint}
  \tikzphysicsassertpoint{Curve}{curve-100}{Curve}{curve-end}
    {curved ramp curve-100 endpoint}
  \tikzphysicsgetpoint{Curve}{normal-100}
  \tikzphysicsassertdim{\tikzphysicstestx}{5.5cm}{curved ramp top outward normal x}
  \tikzphysicsassertdim{\tikzphysicstesty}{4cm}{curved ramp top outward normal y}

  \node[curved-ramp-left, curved ramp radius=4cm, curved ramp angle=90]
    (CurveLeft) at (0,-5) {};
  \tikzphysicsgetpoint{CurveLeft}{surface-end}
  \tikzphysicsassertdim{\tikzphysicstestx}{-6cm}{left curved ramp mirrors x}
  \tikzphysicsassertdim{\tikzphysicstesty}{-1cm}{left curved ramp retains rise}
\end{tikzpicture}

\begin{tikzpicture}[scale=0.2,every node/.append style={transform shape}]
  \node[concave-mirror, mirror radius=5, mirror thickness=0.25,
        mirror aperture angle=30] (Mirror) at (0,0) {};
  \tikzphysicsassertpoint{Mirror}{surface-0}{Mirror}{surface-bottom}
    {concave mirror surface-0 endpoint}
  \tikzphysicsassertpoint{Mirror}{surface-100}{Mirror}{surface-top}
    {concave mirror surface-100 endpoint}
  \tikzphysicsassertpoint{Mirror}{back-0}{Mirror}{back-bottom}
    {concave mirror back-0 endpoint}
  \tikzphysicsassertpoint{Mirror}{back-100}{Mirror}{back-top}
    {concave mirror back-100 endpoint}
  \tikzphysicsassertpoint{Mirror}{80}{Mirror}{surface-80}
    {concave mirror shorthand 80 uses reflecting surface}
  \node[convex-mirror, mirror radius=5, mirror thickness=0.25,
        mirror aperture angle=30] (ConvexMirror) at (0,-5) {};
  \tikzphysicsgetpoint{ConvexMirror}{surface-mid}
  \ifdim\tikzphysicstestx<0pt
    \TYPE{PASS: convex mirror reflecting arc is on the left}
  \else
    \TYPE{FAIL: convex mirror reflecting arc is not on the left}
  \fi
  \TYPE{PASS: concave and convex mirror styles compile}
\end{tikzpicture}

\begin{tikzpicture}[scale=0.2,every node/.append style={transform shape}]
  \node[convex-lens, convex lens radius=5, convex lens thickness=0.2,
        convex lens aperture angle=25] (Convex) at (0,0) {};
  \tikzphysicsassertpoint{Convex}{front-0}{Convex}{front-bottom}
    {convex lens front-0 endpoint}
  \tikzphysicsassertpoint{Convex}{front-100}{Convex}{front-top}
    {convex lens front-100 endpoint}
  \tikzphysicsassertpoint{Convex}{back-0}{Convex}{back-bottom}
    {convex lens back-0 endpoint}
  \tikzphysicsassertpoint{Convex}{back-100}{Convex}{back-top}
    {convex lens back-100 endpoint}
  \tikzphysicsassertpoint{Convex}{50}{Convex}{front-50}
    {convex lens shorthand 50 uses front surface}

  \node[concave-lens, concave lens radius=5, concave lens thickness=0.2,
        concave lens aperture angle=25] (Concave) at (2,0) {};
  \tikzphysicsassertpoint{Concave}{front-0}{Concave}{front-bottom}
    {concave lens front-0 endpoint}
  \tikzphysicsassertpoint{Concave}{front-100}{Concave}{front-top}
    {concave lens front-100 endpoint}
  \tikzphysicsassertpoint{Concave}{back-0}{Concave}{back-bottom}
    {concave lens back-0 endpoint}
  \tikzphysicsassertpoint{Concave}{back-100}{Concave}{back-top}
    {concave lens back-100 endpoint}
  \tikzphysicsassertpoint{Concave}{80}{Concave}{front-80}
    {concave lens shorthand 80 uses front surface}

  \node[slab, slab width=1.2, slab height=3] (Slab) at (4,0) {};
  \tikzphysicsassertpoint{Slab}{front-0}{Slab}{front-bottom}
    {slab front-0 endpoint}
  \tikzphysicsassertpoint{Slab}{front-100}{Slab}{front-top}
    {slab front-100 endpoint}
  \tikzphysicsassertpoint{Slab}{back-0}{Slab}{back-bottom}
    {slab back-0 endpoint}
  \tikzphysicsassertpoint{Slab}{back-100}{Slab}{back-top}
    {slab back-100 endpoint}
  \tikzphysicsassertpoint{Slab}{50}{Slab}{front-50}
    {slab shorthand 50 uses front surface}

  \node[prism, prism width=3, prism apex angle=60] (Prism) at (8,0) {};
  \tikzphysicsassertpoint{Prism}{base-0}{Prism}{base-left}
    {prism base-0 endpoint}
  \tikzphysicsassertpoint{Prism}{base-100}{Prism}{base-right}
    {prism base-100 endpoint}
  \tikzphysicsassertpoint{Prism}{right-100}{Prism}{apex}
    {prism right-100 endpoint}
  \tikzphysicsassertpoint{Prism}{left-0}{Prism}{apex}
    {prism left-0 endpoint}
  \tikzphysicsassertpoint{Prism}{80}{Prism}{left-80}
    {prism shorthand 80 uses left entry face}
\end{tikzpicture}

\begin{tikzpicture}
  \node[physicsblock, physics block width=1, physics block height=10mm] (Block) at (0,0) {};
  \tikzphysicsgetpoint{Block}{east}
  \tikzphysicsassertdim{\tikzphysicstestx}{0.5cm}{bare block width is centimetres}
  \tikzphysicsgetpoint{Block}{north}
  \tikzphysicsassertdim{\tikzphysicstesty}{5mm}{explicit block height unit is preserved}
\end{tikzpicture}

\begin{tikzpicture}
  \node[spring, minimum width=4cm, pre length=5mm,
        post length=7mm, amplitude=4.5pt,
        segment length=4.5pt] (Spring) at (0,0) {};
  \tikzphysicsgetpoint{Spring}{start}
  \tikzphysicsassertdim{\tikzphysicstestx}{-2cm}{spring start follows native minimum width}
  \tikzphysicsgetpoint{Spring}{end}
  \tikzphysicsassertdim{\tikzphysicstestx}{2cm}{spring end follows native minimum width}
  \tikzphysicsgetpoint{Spring}{coil-start}
  \tikzphysicsassertdim{\tikzphysicstestx}{-1.5cm}{spring pre length anchor}
  \tikzphysicsgetpoint{Spring}{coil-end}
  \tikzphysicsassertdim{\tikzphysicstestx}{1.3cm}{spring post length anchor}
  \node[physicsspring, minimum width=3cm,
        physics spring amplitude=3pt, rotate=20] at (5,0) {};
  \TYPE{PASS: spring concise and collision-safe forms compile}
\end{tikzpicture}

\begin{tikzpicture}
  \coordinate (StringA) at (-3,-1);
  \coordinate (StringB) at (3,-1);
  \node[physicspulley, physics pulley diameter=1] (StringPulley) at (0,0) {};
  \physicsstringoverpulley{StringA}{StringPulley}{StringB}
  \physicsstringoverpulley[
    physics string start solution=1,
    physics string end solution=2,
    physics string wrap=shortest,
    dashed]
    {StringA}{StringPulley}{StringB}
  \physicsstringoverpulley[physics string route=over]{StringA}{StringPulley}{StringB}
  \physicsstringoverpulley[physics string route=under]{StringA}{StringPulley}{StringB}
  \physicsstringoverpulley[physics string route=shortest]{StringA}{StringPulley}{StringB}
  \TYPE{PASS: tangent pulley string default, explicit, and named routes compile}
\end{tikzpicture}

\begin{tikzpicture}[scale=0.5,every node/.append style={transform shape}]
  \node[platform, minimum width=5cm, minimum height=2cm,
        physics left wall angle=135, physics right wall angle=45]
        (ShortPlatform) at (0,0) {};
  \node[physicsplatform-both, minimum width=5cm, minimum height=2cm,
        physics left wall angle=135, physics right wall angle=45]
        (LongPlatform) at (0,0) {};
  \tikzphysicsassertpoint{ShortPlatform}{left-corner}{LongPlatform}{left-corner}
    {short platform matches collision-safe platform}
  \tikzphysicsassertpoint{ShortPlatform}{right-corner}{LongPlatform}{right-corner}
    {short platform right corner matches collision-safe platform}

  \node[wedge, wedge width=4cm, wedge angle=30] (ShortWedge) at (0,-3) {};
  \node[physicswedge, physics wedge width=4cm, physics wedge angle=30]
    (LongWedge) at (0,-3) {};
  \tikzphysicsassertpoint{ShortWedge}{slope-mid}{LongWedge}{slope-mid}
    {concise wedge keys match collision-safe aliases}
  \node[wedge, wedge width=4cm, wedge height=2cm]
    (ShortHeightWedge) at (0,-6) {};
  \TYPE{PASS: wedge height concise key compiles}
  \node[block, minimum width=1cm, minimum height=8mm] (ShortBlock) at (5,-3) {};
  \node[spring, minimum width=2cm] (ShortSpring) at (5,-5) {};
  \node[pulley, minimum size=1cm] (ShortPulley) at (7,-3) {};
  \node[concave-mirror, mirror radius=5cm] at (10,-3) {};
  \node[convex-mirror, mirror radius=5cm] at (10,-3) {};
  \node[convex-lens, convex lens radius=5cm] at (10,-3) {};
  \node[concave-lens, concave lens radius=5cm] at (10,-3) {};
  \node[slab, minimum width=1cm, minimum height=2cm] at (10,-3) {};
  \node[prism, minimum width=2cm, minimum height=1.7cm] at (10,-3) {};
  \node[ground, minimum width=2cm] at (0,-6) {};
  \node[ceiling, minimum width=2cm] at (3,-6) {};
  \node[wall-left, minimum height=2cm] at (6,-6) {};
  \node[wall-right, minimum height=2cm] at (9,-6) {};
  \TYPE{PASS: all concise public styles compile, including optics components}
\end{tikzpicture}

\END
\end{document}
