% \iffalse meta-comment
%
% File: sunpath.dtx Copyright (C) 2024 Hong-Phuc Bui
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    https://www.latex-project.org/lppl.txt
%
%
% -----------------------------------------------------------------------
%
% The development version of the bundle can be found at
%
%    https://github.com/hpb-htw/sunpath
%
% for those people who are interested.
%
% -----------------------------------------------------------------------
% \fi
% 
% ^^A To get version of latex run:
% ^^A `latex '\typeout{\fmtversion}\stop' | grep LaTeX2e`
%
% \iffalse
%<package>\NeedsTeXFormat{LaTeX2e}[2022/11/01]
%<package>\ProvidesPackage{sunpath}[2024/10/20 v0.5 Draw Sun Path]
% \fi

% \changes{v0.5}
%         {2024/10/20}
%         {replace prefix "draw" in exposed commands by "sp"}
% \changes{v0.4-Alpha}
%         {2024/10/20}
%         {rename option altitude projection to altitude mapping}
% \changes{v0.3-Alpha}
%         {2024/10/16}
%         {add style option in exposed commands; 
%          let build.lua read version information from sunpath.dtx file}
%
% \changes{v0.2-Alpha}
%         {2024/10/16}
%         {Small fixes in README.md and document}
%
% \changes{v0.1-Alpha}
%         {2024/10/10}
%         {Initial implementation}


% \section{Implementation}
%
% \subsection{Package Dependenies}
%
%    \begin{macrocode}
\RequirePackage{expl3}
\RequirePackage{tikz}
%    \end{macrocode}
%
% Load necsessary \texttt{tikz}-libraries.
%    \begin{macrocode}
\usetikzlibrary{calc,math,through}
%    \end{macrocode}




% \subsection{\texttt{tikz}-Options for the new coordinate system}
% Setup  options for \texttt{tikzpicture} environment.
%
% \DescribeMacro{spradius} The radius of the 0° Altitude circle, default 5.5. 
% This value can be accessed via macro \verb:\spradius:.
%
% \DescribeMacro{altitude mapping} 
% How the altitude of the sun is mapped on the sunpath diagram. 
% This mapping is a function $f(\theta): [-90,90] \to [0, r]$, where $r$ is saved in \verb|\spradius|.
%
% Valid values are \texttt{spherical} and \texttt{equidistance}.
% Its default value is \texttt{spherical}.
%
% This value can be accessed via macro \verb:\altmapping:.

% These options can be used like:
% 
% \begin{verbatim}
% \begin{tikzpicture}[spradius=6,altitude projection=equidistance]
% \coordinate (sunrise) at (sunpath cs:azi=105, alt=66.6);
% \end{tikzpicture}
% \end{verbatim}
%
%    \begin{macrocode}
\pgfkeys{/tikz/.cd,
  spradius/.store in=\spradius,
  spradius=5.5,
  altitude mapping/.store in = \altmapping,
  altitude mapping=spherical
}
%    \end{macrocode}
%


% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \subsection{Define the new coordinate system \texttt{sunpath}}
\makeatletter

% \subsubsection{Azimuth and altitude}
% Define component \texttt{azi} (=Azimuth angle) and \texttt{alt} (=Altidude angle) for the coordinate system \texttt{sunpath}.
%    \begin{macrocode}
\tikzset{
  cs/azi/.store in=\tikz@cs@azi,
  cs/alt/.store in=\tikz@cs@alt,
}
%    \end{macrocode}


% \subsubsection{Projection functions}
% Funtions to map the atitude of the sun to the altitude value on the sun path diagram.
% 
% \DescribeMacro{spherical} 
% maps an altitude angle $\theta$ to the altitude radius on the diagram with the function 
%   \[s (\theta) = r \cos(\theta). \]
%
% \DescribeMacro{equidistance}
% maps an altitude angle $\theta$ to the altitude radius on the diagram with the function
%    \[e (\theta) = r - r \cdot \frac{\left\lvert \theta \right\rvert}{90}. \]
%
% \DescribeMacro{altradius}
% this function is used in the coordinate system \texttt{sunpath} to determinate the altitude 
% radius of an azimuth angle on the sun path chart. 
% It depends on the value of the option \verb:altitude projection:.
% 
%
% \DescribeMacro{aziangle}
% maps the azimuth angle $\Phi$ to the azimuth angle on the diagram with the function
%     \[ a(\Phi) = 90 - \Phi. \]
%    \begin{macrocode}
\tikzset{  
  declare function = {
      spherical(\alt) = \spradius * cos(\alt);
      equidistance(\alt) = \spradius - \spradius*abs(\alt)/90;
      altradius(\alt) = \altmapping(\alt); 
      aziangle(\x) = 90 - \x;
  }
} 
%    \end{macrocode}
%


% \subsubsection{Coordinate system \texttt{sunpath}}
%    \begin{macrocode}
\tikzdeclarecoordinatesystem{sunpath}%
{
    \tikzset{cs/.cd,azi=0,alt=0,#1}
    \tikzmath{      
      \r = altradius(\tikz@cs@alt);
      \angle = aziangle(\tikz@cs@azi);
    }
    \pgfpointadd{\pgfpointxy{0}{0}}{%
        \pgfpointpolarxy{\angle}{\r}
    }
}
%    \end{macrocode}
\makeatother 



% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \subsection{Setup optical options for sunpath diagram}
% These are pre-defined \TikZ{} style for components of the chart. They can be easily changed by using \cmd{\tikzset}.
%
% \DescribeMacro{sunpath grid} \tikz{\draw [sunpath grid] (0,0) -- (1,0);} style for azimuth lines and altitude circles 
%
% \DescribeMacro{sunpath tick} \tikz{\draw [sunpath tick] (0,0) -- (4pt,0);} style for ticks around the horizon line
%
% \DescribeMacro{sunpath minor tick} \tikz{\draw [sunpath minor tick] (0,0) -- (4pt,0);} style for minor ticks around horizon line
%
% \DescribeMacro{altitude label} \tikz{\node[altitude label] {80};}
%
% \DescribeMacro{azimuth label}  \tikz{\node[altitude label] {350};} style for text label of altitude circle respective azimuth line
% 
% \DescribeMacro{direction label} \tikz{\node[direction label] {N E S W}; } style for text label of four directions
%
%    \begin{macrocode}
\tikzset{
  sunpath grid/.style={help lines,color=blue!45!white!80},
  sunpath tick/.style={draw,thick,color=blue!90!white!80},
  sunpath minor tick/.style={draw,thin,color=blue!90!white!80},
  altitude label/.style={
      font=\footnotesize\sffamily,
      fill=white,minimum width={width("90")+2pt},
      inner sep=0.5pt
  },
  azimuth label/.style={
      font=\footnotesize\sffamily,
      minimum width={width("360")+2pt},
      inner sep=0.5pt
  },
  direction label/.style={
      font=\normalsize\rmfamily
  }
}
%    \end{macrocode}


% \subsection{Expose some commands for end-user}

% \DescribeMacro{\spcrosshair} \oarg{style}
%
% Draws a thin line from North to South and a thin line from East to West. 
% Default value of \oarg{style} is \texttt{sunpath grid}.
%
%    \begin{macrocode}
\NewDocumentCommand\spcrosshair{O{sunpath grid}}{
    \draw[#1] (-\spradius,0) -- (\spradius,0);
    \draw[#1] (0,-\spradius) -- (0,\spradius);
}
%    \end{macrocode}




% \DescribeMacro{\spgeodirection} \oarg{offset}\oarg{style}
%
%
% Puts four geographic directions North, East, South, West around the horinzon line.
% \oarg{offset} is the distance from horizon to the \TikZ{} node of the directions.
% Its default value is 22pt. 
% Set it to zero causes that the directions are set very near to the horizon line.
%    \begin{macrocode}
\NewDocumentCommand\spgeodirection{O{22pt} O{direction label}}{
  \foreach \dname / \dgrad in {N/0, E/90, S/180, W/270}{
      \tikzmath{
        \polarangle = aziangle(\dgrad);
      }
      \coordinate (D) at (\polarangle:\spradius cm + #1);
      \node[#2,anchor=270-\dgrad] at (D) {\dname};
  }
}
%    \end{macrocode}




% \DescribeMacro{\spaltitudecircle}  \marg{range}\oarg{style}
%
% Draws altitude circle given by \marg{range}. 
% The argument \marg{range} must be a valid \TikZ-range, which can be used in \cmd{\foreach}.
% For example \verb|{{10,20,...,80,85}}|.
% The argument \oarg{style} define the style of altitude circles, default is \texttt{sunpath~grid}.
%    \begin{macrocode}
\NewDocumentCommand\spaltitudecircle{m O{sunpath grid}}{
  \foreach \altitude in #1 {
    \coordinate (A) at (sunpath cs:azi=0,alt=\altitude) ;  
    \path[draw,sunpath grid] (0,0) circle[radius=altradius(\altitude)];
  }
}
%    \end{macrocode}




% \DescribeMacro{\spaltitudelabel}  \marg{range}\oarg{azimuth}\oarg{style}
% 
% Draws the labels of altitude circles given by \marg{range}. 
% Range must be an in \TikZ{} valid numeric range which can be used in \cmd{\foreach}.
% For example \verb|{{10,20,...,80}}|
% The labels are placed along the azimuth \oarg{azimuth} (default 135)
% and typeset with style \oarg{style} (default \texttt{altitude label}).
%
%    \begin{macrocode}
\NewDocumentCommand\spaltitudelabel{m O{135} O{altitude label}}{
  \foreach \altitude in #1 {
      \coordinate (A) at (sunpath cs:azi=#2,alt=\altitude) ;      
      \node [anchor=east,#3] at (A) {\altitude};  
    }
}
%    \end{macrocode}




% \DescribeMacro{\spazimuthlabel}  \marg{range}\oarg{style}
%
%    \begin{macrocode}
\NewDocumentCommand\spazimuthlabel{m O{azimuth label}}{
  \foreach \azimuth in #1 {
      \tikzmath{
        \polarangle = aziangle(\azimuth);
      }
      \coordinate (D) at (\polarangle:\spradius cm + 13pt);
      \node[#2] at (D) {\azimuth};
  }
}
%    \end{macrocode}




% \DescribeMacro{\spazimuthline} \marg{range}\marg{start~alt}\marg{end~alt}
%
%    \begin{macrocode}
\NewDocumentCommand\spazimuthline{m m m}{
  \foreach \azimuth in #1{
      \draw[sunpath grid]
        (sunpath cs:azi=\azimuth,alt={#2}) -- (sunpath cs:azi=\azimuth,alt={#3});
  }
}
%    \end{macrocode}




% \DescribeMacro{\spazimuthtick}  \oarg{major}\oarg{minor}\oarg{mid}
% 
% Draws ticks along and outside the horizon circle. The optional arguments \oarg{major},
% \oarg{minor} and \oarg{mid} are the length of major ticks (every 10° from Zero),
% minor ticks (every 1°, from 1°) and the length of the middle ticks (every 30°, from 15°). 
% Their default values are 6pt, 2.5pt and 5pt.
%
%    \begin{macrocode}
\NewDocumentCommand\spazimuthtick{O{6pt} O{2.5pt} O{5pt}}{
  \foreach \azimuth in {10,20,...,360}{
    \tikzmath{      
        \pa = aziangle(\azimuth);
    }
    \path[sunpath tick] (\pa:\spradius) -- (\pa:{\spradius cm + #1});
  }
  
  \foreach \azimuth in {1,2,...,360}{
    \tikzmath{      
        \pa = aziangle(\azimuth);
    }
    \path[sunpath minor tick] (\pa:\spradius) -- (\pa:{\spradius cm + #2});
  }
  
  \foreach \azimuth in {15,45,...,345}{
      \tikzmath{      
          \pa = aziangle(\azimuth);
      }
      \path[sunpath minor tick] (\pa:\spradius) -- (\pa:{\spradius cm + #3});
    }  
}
%    \end{macrocode}




%%%%%%%%%%%%%%
\endinput
%%%%%%%%%%%%%%


