%% physketch.optics.sty
%% Optics part of physketch: rays, light sources, lenses, screens and
%% mirrors.
%%
%% Copyright (C) 2024-2026 Azamat Gimaev
%% This work may be distributed and/or modified under the conditions of
%% the LaTeX Project Public License, either version 1.3c of this license
%% or (at your option) any later version.
\NeedsTeXFormat{LaTeX2e}[2020/10/01]
\ProvidesPackage{physketch.optics}
  [2026/10/20 v0.1.0 physketch: optics]

\RequirePackage{physketch.general}

\pgfqkeys{/physketch}{
  screen distance/.initial = 1.2mm,
  mirror width/.initial    = 2mm,
}

\pgfdeclareverticalshading{physketch@mirror}{100bp}
  {color(0bp)=(black!45); color(100bp)=(black!8)}

% ---------------------------------------------------------------------
% Rays
% ---------------------------------------------------------------------
\tikzset{
  ray/.style           = {draw=ray#1},
  ray/.default         = 1,
  virtual ray/.style   = {draw=ray#1, dashed},
  virtual ray/.default = 1,
  optical axis/.style  = {ultra thin, dash dot},
  % an object (an arrow from A to B) and its virtual image
  object/.style         = {thick, ->},
  virtual object/.style = {thick, ->, dashed},
}

% ---------------------------------------------------------------------
% Screens and mirrors
% ---------------------------------------------------------------------
\tikzset{
  % a thick line with sparse hatching behind it
  screen/.style  = {thick, preaction={physketch/band={right}%
    {\pgfkeysvalueof{/physketch/hatch depth}}{hatch}%
    {\pgfkeysvalueof{/physketch/screen distance}}}},
  screen'/.style = {thick, preaction={physketch/band={left}%
    {\pgfkeysvalueof{/physketch/hatch depth}}{hatch}%
    {\pgfkeysvalueof{/physketch/screen distance}}}},
  % a thick line with a grey gradient behind it
  mirror/.style  = {thick, preaction={physketch/band={right}%
    {\pgfkeysvalueof{/physketch/mirror width}}{shade}{physketch@mirror}}},
  mirror'/.style = {thick, preaction={physketch/band={left}%
    {\pgfkeysvalueof{/physketch/mirror width}}{shade}{physketch@mirror}}},
}

% ---------------------------------------------------------------------
% Light sources
% ---------------------------------------------------------------------
% \lightsource[name=S, radius=0.15cm, halo=0.2cm, fill=white]{(x,y)}
% The source is a circular node `S' of radius `halo' filled with `fill':
% lines drawn from (S) start at the edge of the halo, so rays do not
% cross the source.
\pgfqkeys{/physketch/light source}{
  name/.initial   = {},
  radius/.initial = 0.15cm,
  halo/.initial   = 0.2cm,
  fill/.initial   = white,
  .unknown/.code  = \physketch@unknown{#1},
}
\NewDocumentCommand\lightsource{O{}m}{%
  \begingroup
    \def\physketch@opts{}%
    \pgfqkeys{/physketch/light source}{#1}%
    \physketch@getname{light source}%
    \pgfmathsetlengthmacro\physketch@r{\pgfkeysvalueof{/physketch/light source/radius}}%
    \pgfmathsetlengthmacro\physketch@size
      {2*(\pgfkeysvalueof{/physketch/light source/halo})}%
    \edef\physketch@do{\noexpand\node[transform shape, circle,
      fill=\pgfkeysvalueof{/physketch/light source/fill}, inner sep=0pt,
      outer sep=0pt, minimum size=\physketch@size,
      \unexpanded\expandafter{\physketch@opts}] (\physketch@name) at
      \unexpanded{#2} {};}%
    \physketch@do
    \begin{scope}[shift={(\physketch@name.center)}]
      \foreach \physketch@i in {0,30,...,330}
        \draw[ultra thin] (\physketch@i:0.05cm) -- (\physketch@i:\physketch@r);
      \draw[fill=white] (0,0) circle[radius=0.05cm];
    \end{scope}
  \endgroup
}

% ---------------------------------------------------------------------
% Lenses
% ---------------------------------------------------------------------
% \lens[name=L, height=3cm, diverging]{(x,y)}
% The lens is a node `L' of zero width with anchors L.north, L.south, ...
\tikzset{
  physketch/lens/.style = {thick,
    {Straight Barb[length=2mm, width=2.5mm]}-{Straight Barb[length=2mm, width=2.5mm]}},
  physketch/diverging lens/.style = {thick,
    {Straight Barb[length=2mm, width=2.5mm, reversed]}-%
    {Straight Barb[length=2mm, width=2.5mm, reversed]}},
}
\newif\ifphysketch@diverging
\pgfqkeys{/physketch/lens}{
  name/.initial    = {},
  height/.initial  = 3cm,
  diverging/.code  = \physketch@divergingtrue,
  converging/.code = \physketch@divergingfalse,
  .unknown/.code   = \physketch@unknown{#1},
}
\NewDocumentCommand\lens{O{}m}{%
  \begingroup
    \def\physketch@opts{}%
    \physketch@divergingfalse
    \pgfqkeys{/physketch/lens}{#1}%
    \physketch@getname{lens}%
    \pgfmathsetlengthmacro\physketch@h{\pgfkeysvalueof{/physketch/lens/height}}%
    \edef\physketch@do{\noexpand\node[transform shape, rectangle, inner sep=0pt, outer sep=0pt,
      minimum width=0pt, minimum height=\physketch@h,
      \unexpanded\expandafter{\physketch@opts}] (\physketch@name) at
      \unexpanded{#2} {};}%
    \physketch@do
    \ifphysketch@diverging
      \draw[physketch/diverging lens] (\physketch@name.south) -- (\physketch@name.north);
    \else
      \draw[physketch/lens] (\physketch@name.south) -- (\physketch@name.north);
    \fi
  \endgroup
}

\endinput
