summaryrefslogtreecommitdiff
path: root/macros/luatex
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2024-08-22 03:03:13 +0000
committerNorbert Preining <norbert@preining.info>2024-08-22 03:03:13 +0000
commitb705e74a380bef7cb2ca827bff29f28062cbdbe2 (patch)
tree7c177db5522f64d976c77f47ad1bfcfc9af27668 /macros/luatex
parent53ed061f98728598170f14eeb5476b2fed9499f8 (diff)
CTAN sync 202408220303
Diffstat (limited to 'macros/luatex')
-rw-r--r--macros/luatex/latex/domaincoloring/Changes1
-rw-r--r--macros/luatex/latex/domaincoloring/README.md10
-rw-r--r--macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.bib27
-rw-r--r--macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.pdfbin0 -> 7132684 bytes
-rw-r--r--macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.tex249
-rw-r--r--macros/luatex/latex/domaincoloring/doc/hsv.pngbin0 -> 533343 bytes
-rw-r--r--macros/luatex/latex/domaincoloring/latex/domaincoloring.sty71
-rw-r--r--macros/luatex/latex/domaincoloring/lua/complex-numbers.lua357
-rw-r--r--macros/luatex/latex/domaincoloring/lua/domaincoloring-functions.lua74
-rw-r--r--macros/luatex/latex/domaincoloring/lua/domaincoloring.lua289
10 files changed, 1078 insertions, 0 deletions
diff --git a/macros/luatex/latex/domaincoloring/Changes b/macros/luatex/latex/domaincoloring/Changes
new file mode 100644
index 0000000000..1498297672
--- /dev/null
+++ b/macros/luatex/latex/domaincoloring/Changes
@@ -0,0 +1 @@
+0.01 2024-08-21 - first CTAN version
diff --git a/macros/luatex/latex/domaincoloring/README.md b/macros/luatex/latex/domaincoloring/README.md
new file mode 100644
index 0000000000..3a57b45ee4
--- /dev/null
+++ b/macros/luatex/latex/domaincoloring/README.md
@@ -0,0 +1,10 @@
+# README #
+Package domaincoloring creates a colored
+representation of the domain of complex function.
+
+
+%% This file is distributed under the terms of the LaTeX Project Public
+%% License from CTAN archives in directory macros/latex/base/lppl.txt.
+%% Either version 1.3 or, at your option, any later version.
+
+hvoss@tug.org \ No newline at end of file
diff --git a/macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.bib b/macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.bib
new file mode 100644
index 0000000000..d109070c92
--- /dev/null
+++ b/macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.bib
@@ -0,0 +1,27 @@
+@online{wikipedia,
+ author = {{\WikipediA}},
+ sortlabel = {Wikipedia},
+ sortname = {Wikipedia},
+ title = {DOmain Coloring},
+ date = {2024-08-18},
+ urldate = {2024-08-18},
+ url = {https://en.wikipedia.org/wiki/Domain_coloring},
+}
+
+@online{features,
+ author = {{vismath}},
+ title = {Thema Domain Coloring},
+ date = {2024-08-18},
+ urldate = {2024-08-18},
+ url = {https://www.vismath.eu/de/blog/domain-coloring/},
+}
+
+
+@online{fu,
+ author = {Konstantin Poelke and Konrad Polthier},
+ title = {Domain Coloring of Complex Functions},
+ url = {https://www.mi.fu-berlin.de/en/math/groups/ag-geom/publications/db/ieee_article_old_low_v3_1.pdf},
+ urldate = {2024-08-18},
+ date = {2024-08-18},
+}
+
diff --git a/macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.pdf b/macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.pdf
new file mode 100644
index 0000000000..19e3b30033
--- /dev/null
+++ b/macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.pdf
Binary files differ
diff --git a/macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.tex b/macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.tex
new file mode 100644
index 0000000000..80377e25ae
--- /dev/null
+++ b/macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.tex
@@ -0,0 +1,249 @@
+%% $Id: domaincoloring-doc.tex 945 2024-08-21 19:30:48Z herbert $
+%
+% Copying and distribution of this file, with or without modification,
+% are permitted in any medium, without royalty.
+
+\listfiles
+\PassOptionsToPackage{table}{xcolor}
+\documentclass[fontsize=11pt,paper=a4,twoside=on,abstract=on,usegeometry]{scrartcl}
+\usepackage[bmargin=1cm,tmargin=1cm,includeheadfoot]{geometry}
+
+\usepackage{unicode-math}
+\usepackage[RM={Scale=0.94},
+ SS={Scale=0.94},
+ SScon={Scale=0.94},
+ TT={Scale=MatchLowercase,FakeStretch=0.9},
+ DefaultFeatures={Ligatures=TeX}]{libertinus-otf}
+\setmonofont{AnonymousPro}[FakeStretch=0.9,Scale=MatchLowercase]
+\usepackage[english]{babel}
+%\usepackage[autostyle]{csquotes}
+%\DeclareQuoteStyle{polish}{,,}{''}{«}{»}
+
+\usepackage{biblatex}
+\addbibresource{\jobname.bib}
+\usepackage{array,multido}
+\usepackage{metalogo} % for \XeTeX logo
+\usepackage{booktabs} % for examples
+\usepackage{xltabular} % for examples
+\usepackage{enumitem}
+\setlist{noitemsep,nosep}
+\usepackage{domaincoloring}
+
+\usepackage{multicol,hvlogos} % for Wikipedia W
+
+\usepackage{listings}
+\lstset{columns=fixed,basicstyle=\ttfamily\small}
+
+\pagestyle{headings}
+
+\usepackage[colorlinks,hyperfootnotes=false]{hyperref}
+% define \code for url-like breaking of typewriter fragments.
+\ifx\nolinkurl\undefined \let\code\url \else \let\code\nolinkurl \fi
+
+% Define \cs to prepend a backslash, and be unbreakable:
+\DeclareRobustCommand\cs[1]{\mbox{\texttt{\char`\\#1}}}
+
+\let\Lkeyword\texttt
+
+\title{Domain Coloring of complex functions}
+\author{Herbert Voß}
+\begin{document}
+\maketitle
+\tableofcontents
+
+
+\section{Introduction}
+
+\subsection{Loading the package}
+The package \texttt{domaincoloring} creates acolored interpretation of the
+domain of a complex function. The package itself has no options and should be loaded as
+usual:
+
+\begin{verbatim}
+\usepackage{domaincoloring}
+\end{verbatim}
+
+The needs the following Lua modules:
+
+\begin{itemize}
+\item \texttt{domaincoloring.lua} the main module
+\item \texttt{complex-numbers.lua} for complex math operations
+\item \texttt{domaincoloring-functions.lua} for predefined complex functions
+\end{itemize}
+
+The function module has to be managed by the user himself, if needed.
+
+
+
+\subsection{Using the macro}
+
+There is only one macro which does the external call of the Lua program \verb|domaincoloring.lua|.
+This program creates the image which is then included into the document. The \LaTeX-run needs
+the \verb|--shell-escape| option to allow the external run of the program to convert the created
+ppm-file into a png file..
+
+
+\begin{verbatim}
+\DomainColoring[options]{complex function}
+\end{verbatim}
+
+
+\clearpage
+\subsection{Options}
+
+\noindent
+\begin{xltabular}{\linewidth}{@{} >{\ttfamily}l l X @{}}\\\toprule
+\emph{name} & \emph{value} &\emph{meaning}\\\midrule
+domain & {-2,2,-2,2} & the (re,im)-coordinates for the complex system\\
+resolution & 500 & the number of steps for the re,im interval. At the moment only
+for both coordinates the same. Will be in future
+versions different for the both axes. \\
+filename & \cs{jobname-tmp} & name of the created external file, must be unique\\
+grfOptions &scale=0.5 & optional arguments for \cs{includegraphics}\\
+hsvrgb & {phi,1,r} & for the conversion into rgb\\
+funcName & & corresponding to external file\\
+bgcolor & false & change black to white as background\\
+invers & false & invers colors with $color=|color-255|$\\
+\bottomrule
+\end{xltabular}
+
+\section{examples}
+
+\subsection{The default with function $f(z)=z$}
+\begin{lstlisting}
+\DomainColoring{z}\qquad % default filename \jobname-tmp.png
+\end{lstlisting}
+
+\noindent
+\DomainColoring{z}%\qquad
+%\DomainColoring[filename=demo2.png,bgcolor=true]{z}
+
+
+\clearpage
+
+\subsection{Defining domain, color mode, resolution and filename}
+\begin{lstlisting}
+\DomainColoring[domain={-2.5,2.5,-2.5,2.5},resolution=500,
+ grfOptions={width=0.32\linewidth},
+ filename=\jobname-tmp1a]{cmath.cos(z)/cmath.sin(z^4-1)}
+\hfill
+\frame{\DomainColoring[domain={-2.5,2.5,-2.5,2.5},resolution=500,
+ bgcolor=true,grfOptions={width=0.32\linewidth}
+ filename=\jobname-tmp1b]{cmath.cos(z)/cmath.sin(z^4-1)}}
+\hfill
+\frame{\DomainColoring[domain={-2.5,2.5,-2.5,2.5},resolution=500,
+ invers=true,,grfOptions={width=0.32\linewidth}
+ filename=\jobname-tmp1c]{cmath.cos(z)/cmath.sin(z^4-1)}}
+\end{lstlisting}
+
+\noindent
+\DomainColoring[domain={-2.5,2.5,-2.5,2.5},resolution=500,grfOptions={width=0.32\linewidth},
+ filename=\jobname-tmp1a]{cmath.cos(z)/cmath.sin(z^4-1)}
+\hfill
+\frame{\DomainColoring[domain={-2.5,2.5,-2.5,2.5},resolution=500,bgcolor=true,grfOptions={width=0.32\linewidth},
+ filename=\jobname-tmp1b]{cmath.cos(z)/cmath.sin(z^4-1)}}
+\hfill
+\frame{\DomainColoring[domain={-2.5,2.5,-2.5,2.5},resolution=500,invers=true,grfOptions={width=0.32\linewidth},
+ filename=\jobname-tmp1c]{cmath.cos(z)/cmath.sin(z^4-1)}}
+
+\subsection{Option for \cs{includegraphics}}
+
+\begin{lstlisting}
+\DomainColoring[grfOptions={width=0.49\linewidth},filename=\jobname-tmp2a]{cmath.sin(z)}\hfill
+\hfill
+\DomainColoring[grfOptions={width=0.49\linewidth},filename=\jobname-tmp2b]{1/cmath.sin(z)}
+\end{lstlisting}
+
+\noindent
+\DomainColoring[grfOptions={width=0.49\linewidth},filename=\jobname-tmp2a]{cmath.sin(z)}
+\hfill
+\DomainColoring[grfOptions={width=0.49\linewidth},filename=\jobname-tmp2b]{1/cmath.sin(z)}
+
+
+\clearpage
+\subsection{Higher resolution}
+
+\begin{lstlisting}
+\DomainColoring[filename=\jobname-tmp3,resolution=1000,
+ grfOptions={width=0.49\linewidth}]{z^3-1}
+\hfill
+\DomainColoring[filename=\jobname-tmp4,resolution=1000,
+ grfOptions={width=0.49\linewidth}]{(z+1)^2*(z-1)/((z+i)*(z-i)^2)}
+\end{lstlisting}
+
+\noindent
+\DomainColoring[filename=\jobname-tmp3,resolution=1000,
+ grfOptions={width=0.49\linewidth}]{z^3-1}
+\hfill
+\DomainColoring[filename=\jobname-tmp4,resolution=1000,
+ grfOptions={width=0.49\linewidth}]{cmath.sin(z)*cmath.cos(z)}
+
+
+\subsection{hsv to rgb conversion}
+
+The color model (Wikipedia)
+
+\begin{center}
+\includegraphics[width=0.5\linewidth]{hsv}
+
+\url{http://en.wikipedia.org/wiki/File:HSV_color_solid_cylinder_alpha_lowgamma.png}
+\end{center}
+
+
+The complex number $z=x+iy$ is converted into its trogonometrical representation $x=r\cdot \cos\phi$
+and $y=r\cdot \sin\phi$ with $r=\sqrt{x^2+y^2}$. The values $r$ and $\phi$ are now taken as values
+for the hsv color model with a constant second value for saturation. $\phi$ is used
+for hue. For example: \verb|hsv=phi,1,r|, which gives
+
+\begin{lstlisting}
+\DomainColoring[filename=\jobname-tmp5a,resolution=1000,
+ grfOptions={width=0.49\linewidth},hsvrgb={phi,1,r}]{cmath.sin(z)*cmath.sin(0.99*z)}
+\hfill
+\DomainColoring[filename=\jobname-tmp5b,resolution=1000,
+ grfOptions={width=0.49\linewidth}]{cmath.sin(z)*cmath.sin(0.99*z)} % the default
+\end{lstlisting}
+
+\noindent
+\DomainColoring[filename=\jobname-tmp5a,resolution=1000,
+ grfOptions={width=0.49\linewidth},funcName=f10,hsvrgb={phi,1,r}]{cmath.sin(z)*cmath.sin(0.99*z)} % the default
+\hfill
+\DomainColoring[filename=\jobname-tmp5b,resolution=1000,
+ grfOptions={width=0.49\linewidth}]{cmath.sin(z)*cmath.sin(0.99*z)}
+
+%For $r$ and $\phi$ we have to use $r$ and $phi$.
+
+\subsection{External function definition}
+The already existing file \verb|domaincoloring.functions| collects sone
+definitions of complex functions $f(z)$, which can be used from inside \LaTeX\
+with the optional argument \Lkeyword{funcName}. In this case the mandatory argument
+of \cs{DomainColoring} has no meaning and can be empty.
+
+\begin{lstlisting}
+\DomainColoring[filename=\jobname-tmp6a,resolution=1000,
+ domain={-1.5,1.5,-1.5,1.5}, grfOptions={width=0.49\linewidth},
+ hsvrgb={phi,1,1/r}, funcName=f12]{}% using predefined function
+\hfill
+\DomainColoring[filename=\jobname-tmp6b,resolution=2000,
+ domain={-2.3,0.7,-1.5,1.5}, grfOptions={width=0.49\linewidth},
+ hsvrgb={phi,1,1/r},funcName=f13]{}
+\end{lstlisting}
+
+\noindent
+\DomainColoring[filename=\jobname-tmp6a,resolution=1000,
+ domain={-1.5,1.5,-1.5,1.5}, grfOptions={width=0.49\linewidth},
+ hsvrgb={phi,1,1/r}, funcName=f12]{}% using predefined function
+\hfill
+\DomainColoring[filename=\jobname-tmp6b,resolution=2000,
+ domain={-2.3,0.7,-1.5,1.5}, grfOptions={width=0.49\linewidth},
+ hsvrgb={phi,1,1/r},funcName=f13]{}
+
+
+The currently contents of the function file:
+
+\lstinputlisting[language={[5.3]Lua},basicstyle=\small\ttfamily]{domaincoloring-functions.lua}
+
+
+
+\nocite{*}
+\printbibliography
+\end{document}
diff --git a/macros/luatex/latex/domaincoloring/doc/hsv.png b/macros/luatex/latex/domaincoloring/doc/hsv.png
new file mode 100644
index 0000000000..4595b284ab
--- /dev/null
+++ b/macros/luatex/latex/domaincoloring/doc/hsv.png
Binary files differ
diff --git a/macros/luatex/latex/domaincoloring/latex/domaincoloring.sty b/macros/luatex/latex/domaincoloring/latex/domaincoloring.sty
new file mode 100644
index 0000000000..8b17cd6a8c
--- /dev/null
+++ b/macros/luatex/latex/domaincoloring/latex/domaincoloring.sty
@@ -0,0 +1,71 @@
+%% $Id: domaincoloring.sty 945 2024-08-21 19:30:48Z herbert $
+%% This is file `domaincoloring.sty',
+%%
+%% Copyright (C) 2024- Herbert Voss
+%%
+%% It 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.
+%% The latest version of this license is in
+%% http://www.latex-project.org/lppl.txt
+%% and version 1.3c or later is part of all distributions of LaTeX
+%% version 2005/12/01 or later.
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{domaincoloring}
+ [2024/08/21 package for domain coloring of complex values]
+\RequirePackage{xkeyval}
+\RequirePackage{graphicx}
+\RequirePackage{shellesc}
+
+\ifnum\ShellEscapeStatus < 1
+ \PackageError{shellesc}{ShellEscape not enabled! Use --shell-escape}%
+\fi
+
+% Change ^ to normal character to describe functions with lua
+\catcode`\^=11\relax % for power symbol in Lua
+
+\define@key{DCol}{domain}{\def\@domaincoloring@domain{#1}}
+\define@key{DCol}{resolution}{\def\@domaincoloring@res{#1,#1}}
+\define@key{DCol}{bgcolor}{\def\@domaincoloring@bgcolor{#1}}
+\define@key{DCol}{filename}{\def\@domaincoloring@filename{#1}}
+\define@key{DCol}{hsvrgb}{\def\@domaincoloring@hsvrgb{#1}}
+\define@key{DCol}{funcName}{\def\@domaincoloring@funcName{#1}}
+\define@key{DCol}{invers}{\def\@domaincoloring@invers{#1}}
+\define@key{DCol}{grfOptions}{\def\@domaincoloring@grf{#1}}
+
+\def\setDColkeys#1{\edef\x{\noexpand\setkeys{DCol}{#1}}\x}
+
+\setDColkeys{
+ funcName={}, % corresponding to external file
+ hsvrgb={phi+3.14,1,r}, % given (r,phi) of the complex value
+ filename=\jobname-tmp, % the external image filename
+ resolution=500, % pixel per (x|y) interval
+ domain={-2,2,-2,2}, % x|y domain
+ bgcolor=false, % RGB value, changes only 0,0,0 -> 255,255,255
+ invers=false, % 0 or 1 vor inverted colors
+ grfOptions={scale=0.5}, % LaTeX options for the included image
+}%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\def\DomainColoring{\@ifnextchar[\DomainColoring@i{\DomainColoring@i[]}}
+\def\DomainColoring@i[#1]#2{%
+ \begingroup
+ \setDColkeys{#1}%
+ \directlua{
+ require("complex-numbers")
+ require ("domaincoloring")
+ createData("#2",{\@domaincoloring@domain},{\@domaincoloring@res},
+ "\@domaincoloring@funcName","\@domaincoloring@hsvrgb",
+ "\@domaincoloring@bgcolor","\@domaincoloring@invers")}%
+ \typeout{Convert domain.eps file to \@domaincoloring@filename.pdf}%
+ \ShellEscape{epstopdf domain.eps \@domaincoloring@filename.pdf}%
+ %
+ \expandafter\includegraphics\expandafter[\@domaincoloring@grf]{\@domaincoloring@filename.pdf}%
+ \endgroup
+ \ignorespaces
+}
+
+\catcode`\^=7\relax
+\endinput
diff --git a/macros/luatex/latex/domaincoloring/lua/complex-numbers.lua b/macros/luatex/latex/domaincoloring/lua/complex-numbers.lua
new file mode 100644
index 0000000000..7630433984
--- /dev/null
+++ b/macros/luatex/latex/domaincoloring/lua/complex-numbers.lua
@@ -0,0 +1,357 @@
+--Complex Number Library by xXxMoNkEyMaNxXx (_G.cmath)
+--[[
+In pure Lua, use:
+num=complex(re,im)
+or
+num=cx'6+2.5i'
+
+In LuaJIT:
+num=6+2.5i
+
+Functions and constants available in cmath:
+Constants
+-e=2.718281828459
+-i=sqrt(-1)
+-pi=math.pi
+
+Complex creation and extraction functions
+-complex(re,im) creates a complex number from real and imaginary components.
+-re(z) real part of z
+-im(z) imaginary part of z
+-arg(z) argument of z
+
+-abs(z) absolute value of z
+-sqrt(z) = z^0.5
+-pow(x,y) = x^y
+-exp(z) = e^z
+-ln(z) = e^? = z
+-log(b,z) = ln(z)/ln(b)
+
+Trig functions
+-sin(z)
+-cos(z)
+-tan(z)
+
+-sinh(z)
+-cosh(z)
+-tanh(z)
+
+-asin(z)
+-acos(z)
+-atan(z)
+-atan2(y,x)
+
+-asinh(z)
+-acosh(z)
+-atanh(z)
+
+Miscellaneous functions
+-polar(z) returns r,phi = cmath.abs(z),cmath.arg(z)
+-rect(r,phi) returns a complex number from polar = r*e^(i*phi)
+-diff(z) = re(z)^2-im(z)^2
+-zeta(z[,accuracy=1e4]) riemann zeta function
+-lintegrate(f,H,[L=0,n=sensible for H])
+-cx(string) creates a complex number from a string (e.g. "1.1-i" -> 1.1+-1i)
+-cx(re,im) = complex(re,im)
+
+]]
+
+local type=type
+local select=select
+local tonumber=tonumber
+local tostring=tostring
+local setmetatable=setmetatable
+
+e=math.exp(1)
+pi=math.pi
+abs=math.abs
+exp=math.exp
+log=math.log
+cos=math.cos
+sin=math.sin
+cosh=math.cosh
+sinh=math.sinh
+sqrt=math.sqrt
+atan2=math.atan2
+
+forget=1e-14--Forget ridiculously small values. Remove if you want to keep all values. (Not recommended for sanity, shouldn't make a difference in performance or output.)
+--The reason that this is here is because i^2 yields -1+0.0000000000000001i, and (-1)^0.5 yields 0.00000000000000006+i. (Should be just -1 and i)
+
+function istype(c)
+ local t=type(c)
+ return t=="table" and c.type or t
+end
+
+local complex_mt
+--Locally used and desirable functions--
+function re(n)
+ local t=type(n)
+ return t=="table" and (n.re or 0) or t=="number" and n or 0
+end
+
+function im(n)
+ return type(n)=="table" and n.im or 0
+end
+
+function complex(re,im)
+ if forget then
+ if re and abs(re)<=forget then
+ re=0
+ end
+ if im and abs(im)<=forget then
+ im=0
+ end
+ end
+ return setmetatable({re=re or 0,im=im or 0,type="complex"},complex_mt)
+end
+
+function rect(r,phi)--r*e^(i*phi) -> x+iy
+ return complex(r*cos(phi),r*sin(phi))
+end
+
+function arg(z)--Lol, no documentation
+ return atan2(im(z),re(z))
+end
+
+function ln(c)--Natural logarithm
+ local r1,i1=re(c),im(c)
+ return complex(log(r1^2+i1^2)/2,atan2(i1,r1))
+end
+
+-----------------------------------------
+
+--Complex number metatable--
+complex_mt={
+ __add=function(c1,c2)
+ return complex(re(c1)+re(c2),im(c1)+im(c2))
+ end,
+ __sub=function(c1,c2)
+ return complex(re(c1)-re(c2),im(c1)-im(c2))
+ end,
+ __mul=function(c1,c2)
+ local r1,i1,r2,i2=re(c1),im(c1),re(c2),im(c2)
+ return complex(r1*r2-i1*i2,r1*i2+r2*i1)
+ end,
+ __div=function(c1,c2)
+ local r1,i1,r2,i2=re(c1),im(c1),re(c2),im(c2)
+ local rsq=r2^2+i2^2
+ return complex((r1*r2+i1*i2)/rsq,(r2*i1-r1*i2)/rsq)
+ end,
+ __pow=function(c1,c2)--Aww ye
+ local r1,i1,r2,i2=re(c1),im(c1),re(c2),im(c2)
+ local rsq=r1^2+i1^2
+ if rsq==0 then--Things work better like this.
+ if r2==0 and i2==0 then
+ return 1
+ end
+ return 0
+ end
+ local phi=atan2(i1,r1)
+ return rect(rsq^(r2/2)*exp(-i2*phi),i2*log(rsq)/2+r2*phi)
+ end,
+ __unm=function(c)
+ return complex(-re(c),-im(c))
+ end,
+ __tostring=function(c)
+ local iChar = "i"
+ local r,i=re(c),im(c)
+ if i==0 then
+ return tostring(r).." +0"..iChar
+ elseif r==0 then
+ if i==1 then
+ return iChar
+ elseif i==-1 then
+ return "-"..iChar
+ end
+ return i..iChar
+ elseif i<0 then
+ if i==-1 then
+ return r.."-"..iChar
+ end
+ return r.." -"..-i..iChar
+ else
+ if i==1 then
+ return r.."+"..iChar
+ end
+ return r.." +"..i..iChar
+ end
+ end
+}
+----------------------------
+
+--Allow complex arguments for regular math functions with cmath namespace--
+--Note that all these functions still work for regular numbers!
+--The added bonus is that they can handle things like (-1)^0.5. (=i)
+
+i=complex(0,1)
+cmath={e=e,i=i,pi=pi,re=re,im=im,complex=complex,arg=arg,rect=rect,ln=ln}
+_G.cmath=cmath
+
+function cmath.abs(c)--This always returns a pure real value
+ return sqrt(re(c)^2+im(c)^2)
+end
+
+function cmath.diff(c)
+ return re(c)^2-im(c)^2
+end
+
+function cmath.exp(c)
+ return e^c
+end
+
+function cmath.sqrt(c)
+ local num=istype(c)=="complex" and c^0.5 or complex(c)^0.5
+ if im(num)==0 then
+ return re(num)
+ end
+ return num
+end
+
+--Trig functions
+function cmath.sin(c)
+ local r,i=re(c),im(c)
+ return complex(sin(r)*cosh(i),cos(r)*sinh(i))
+end
+function cmath.cos(c)
+ local r,i=re(c),im(c)
+ return complex(cos(r)*cosh(i),sin(r)*sinh(i))
+end
+function cmath.tan(c)
+ local r,i=2*re(c),2*im(c)
+ local div=cos(r)+cosh(i)
+ return complex(sin(r)/div,sinh(i)/div)
+end
+
+--Hyperbolic trig functions
+function cmath.sinh(c)
+ local r,i=re(c),im(c)
+ return complex(cos(i)*sinh(r),sin(i)*cosh(r))
+end
+function cmath.cosh(c)
+ local r,i=re(c),im(c)
+ return complex(cos(i)*cosh(r),sin(i)*sinh(r))
+end
+function cmath.tanh(c)
+ local r,i=2*re(c),2*im(c)
+ local div=cos(i)+cosh(r)
+ return complex(sinh(r)/div,sin(i)/div)
+end
+
+--Caution! Mathematical laziness beyond this point!
+
+--Inverse trig functions
+function cmath.asin(c)
+ return -i*ln(i*c+(1-c^2)^0.5)
+end
+function cmath.acos(c)
+ return pi/2+i*ln(i*c+(1-c^2)^0.5)
+end
+function cmath.atan(c)
+ local r2,i2=re(c),im(c)
+ local c3,c4=complex(1-i2,r2),complex(1+r2^2-i2^2,2*r2*i2)
+ return complex(arg(c3/c4^0.5),-ln(cmath.abs(c3)/cmath.abs(c4)^0.5))
+end
+function cmath.atan2(c2,c1)--y,x
+ local r1,i1,r2,i2=re(c1),im(c1),re(c2),im(c2)
+ if r1==0 and i1==0 and r2==0 and i2==0 then--Indeterminate
+ return 0
+ end
+ local c3,c4=complex(r1-i2,i1+r2),complex(r1^2-i1^2+r2^2-i2^2,2*(r1*i1+r2*i2))
+ return complex(arg(c3/c4^0.5),-ln(cmath.abs(c3)/cmath.abs(c4)^0.5))
+end
+
+--Inverse hyperbolic trig functions. Why do they all look different but give correct results!? e.e
+function cmath.asinh(c)
+ return ln(c+(1+c^2)^0.5)
+end
+function cmath.acosh(c)
+ return 2*ln((c-1)^0.5+(c+1)^0.5)-log(2)
+end
+function cmath.atanh(c)
+ return (ln(1+c)-ln(1-c))/2
+end
+
+--Miscellaneous functions
+function cmath.zeta(s,a)
+ local sum=0
+ for n=a,accuracy or 10000 do
+ sum=sum+n^-s
+ end
+ return sum
+end
+
+--End of non-optimized terrors.
+
+--Linear integration, evenly spaced slices
+--f=function(x),low=0,high=100,slices=10000
+function cmath.lintegrate(f,H,L,n)
+ n=n or floor(10*sqrt(H))
+ L=L or 0
+ local LH=H-L
+ local A=(f(L)+f(H))/2
+ for x=1,n-1 do
+ A=A+f(L+LH*x/n)
+ end
+ return A/n
+end
+
+--cmath.log: Complex base logarithm! One argument (z=c1) gives log(z). Two arguments (b=c1,z=c2) gives log_b(z), which is identical to log(c2)/log(c1).
+function cmath.log(c2,c1)
+ local r1,i1=re(c1),im(c1)
+ local r2,i2=re(c2),im(c2)
+ local r3,i3=log(r1^2+i1^2)/2,atan2(i1,r1)
+ local r4,i4=log(r2^2+i2^2)/2,atan2(i2,r2)
+ local rsq=r4^2+i4^2
+ return complex((r3*r4+i3*i4)/rsq,(r4*i3-r3*i4)/rsq)
+end
+
+cmath.pow=complex_mt.__pow
+---------------------------------------------------------------------------
+
+--These are just some useful tools when working with complex numbers.--
+
+--cmath.polar: x+iy -> r*e^(i*phi) One complex argument, or two real arguments can be given.
+--This is basically return cmath.abs(z),cmath.arg(z)
+function cmath.polar(cx,oy)
+ local x,y
+ if oy then
+ x,y=cx,oy
+ else
+ x,y=re(cx),im(cx)
+ end
+ return sqrt(x^2+y^2),atan2(y,x)
+end
+
+--cmath.cx: Define complex numbers from a string.
+function cmath.cx(a,b)
+ local r,i=0,0
+ if type(a)=="string" and type(b)=="nil" then
+ local query=a:gsub("[^%d.+-i]","")
+ if #query>0 then
+ for sgn,im in query:gmatch'([+-]*)(%d*%.?%d*)i' do
+ i=i+(-1)^select(2,sgn:gsub("-",""))*(tonumber(im) or 1)
+ end
+ for sgn,re in query:gsub("[+-]*%d*%.?%d*i",""):gmatch'([+-]*)(%d*%.?%d*)()' do
+ r=r+(-1)^select(2,sgn:gsub("-",""))*(tonumber(re) or #sgn>0 and 1 or 0)
+ end
+ end
+ else
+ r,i=tonumber(a) or 0,tonumber(b) or 0
+ end
+ if forget then
+ if abs(r)<=forget then
+ r=0
+ end
+ if abs(i)<=forget then
+ i=0
+ end
+ end
+ return complex(r,i)
+end
+-----------------------------------------------------------------------
+
+--Globalize.
+_G.cmath=cmath
+
+-- print(cmath.e^(cmath.i*cmath.pi)+1)
+
diff --git a/macros/luatex/latex/domaincoloring/lua/domaincoloring-functions.lua b/macros/luatex/latex/domaincoloring/lua/domaincoloring-functions.lua
new file mode 100644
index 0000000000..9bd96de0b2
--- /dev/null
+++ b/macros/luatex/latex/domaincoloring/lua/domaincoloring-functions.lua
@@ -0,0 +1,74 @@
+-- $Id: domaincoloring-functions.lua 946 2024-08-21 19:32:10Z herbert $
+
+kpse.set_program_name("luatex")
+
+function f0(z)
+ return cmath.sin(1/z)*cmath.cos(1/z)/z^3+1/z
+end
+
+function f1(z)
+ return cmath.cos(z)/cmath.sin(z^4-1)
+end
+
+function f2(z)
+ local c = complex(1,-1)
+ local d = complex(0,0.28)
+ return cmath.cos(c^2*z^2)/cmath.cos(c*(z-d))
+end
+
+function f3(z)
+ return z*(z+i)^2/(z-i)^2
+end
+
+function f4(z)
+ if abs(z) < 0.1 then
+ return complex(0.001,0.001)
+ else
+ return cmath.sin(1/(z*z))
+ end
+end
+
+function f5(z)
+ return cmath.sqrt(1-1/(z*z)+z^3)
+end
+
+function f9(z)
+ local c = complex(1,-1)
+ local d = complex(1,1)
+ return z^2*c^2*(z*c-1-i)/(z*c-2*d)
+end
+
+function f10(z)
+ local sum = complex(0,0)
+ for n=1,20 do
+ sum = sum + z^n/(1-z^n)
+ end
+ return sum
+end
+
+function f11(z)
+ local iterateNo = 3
+ for n=1,iterateNo do
+ z = z^2
+ end
+ return z
+end
+
+function f12(z) -- julia
+ local iterateNo = 5
+ for n=1,iterateNo do
+ z = z^2 + complex(0.25,-0.5)
+ end
+ return z
+end
+
+function f13(z) -- mandelbrot
+ local iterateNo = 6
+ c = z
+ z = complex(0,0)
+ for n=1,iterateNo do
+ z = z^2 + c
+ end
+ return z
+end
+
diff --git a/macros/luatex/latex/domaincoloring/lua/domaincoloring.lua b/macros/luatex/latex/domaincoloring/lua/domaincoloring.lua
new file mode 100644
index 0000000000..a040e27424
--- /dev/null
+++ b/macros/luatex/latex/domaincoloring/lua/domaincoloring.lua
@@ -0,0 +1,289 @@
+-- $Id: domaincoloring.lua 946 2024-08-21 19:32:10Z herbert $
+
+kpse.set_program_name("luatex")
+
+require("complex-numbers")
+
+local func = io.open("domaincoloring-functions.lua","r")
+if func~=nil then
+ io.close(func)
+ dofile("domaincoloring-functions.lua")
+end
+
+local function HSVtoRGB(h, s, v)
+ i = math.floor(h * 6)
+ f = h * 6 - i
+ p = v * (1 - s)
+ q = v * (1 - f * s)
+ t = v * (1 - (1 - f) * s)
+ no = i // 6
+ if no == 0 then return v,t,p
+ elseif no == 1 then return q,v,p
+ elseif no == 2 then return p,v,t
+ elseif no == 3 then return p,q,v
+ elseif no == 4 then return t,p,v
+ else return v,p,q
+ end
+end
+
+function my_color_scheme(z,hsvrgb)
+ r, phi = cmath.polar(z)
+ h_str,s_str,v_str = hsvrgb:match("([^,]+),([^,]+),([^,]+)")
+-- h = load("return "..h_str)()
+-- s = load("return "..s_str)()
+-- v = load("return "..v_str)()
+ --h,s,v = loadstring("return"..hsvrgb)
+ R,G,B = HSVtoRGB(load("return "..h_str)(),load("return "..s_str)(),load("return "..v_str)()) -- h,s,v) -- (phi+3.14,1,r)
+ return { math.fmod(math.floor(R*255+0.5),255),
+ math.fmod(math.floor(G*255+0.5),255),
+ math.fmod(math.floor(B*255+0.5),255) }
+end
+
+
+--[[
+A raster of Height rows, in order from top to bottom.
+Each row consists of Width pixels, in order from left to
+right. Each pixel is a triplet of red, green, and blue samples,
+in that order. Each sample is represented in pure binary by
+either 1 or 2 bytes. If the Maxval is less than 256, it is
+1 byte. Otherwise, it is 2 bytes. The most significant byte is first.
+A row of an image is horizontal. A column is vertical.
+The pixels in the image are square and contiguous.
+]]
+
+function write_eps_data(name,data,res)
+ print("Lua: writing data file "..name.." ...")
+-- print(data)
+ outFile = io.open(name,"w+") -- Dateiname
+ outFile:write([[
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: (ImageMagick)
+%%Title: (domain.eps)
+%%CreationDate: (2024-08-21T08:45:55+00:00)
+]])
+ outFile:write("%%BoundingBox: -0 -0 "..res[1].." "..res[2].."\n")
+ outFile:write("%%HiResBoundingBox: 0 0 "..res[1].." "..res[2].."\n")
+ outFile:write([[
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 1
+%%Pages: 1
+%%EndComments
+%%BeginDefaults
+%%EndDefaults
+%%BeginProlog
+/DirectClassPacket {
+ currentfile color_packet readhexstring pop pop
+ /number_pixels 3 def
+ 0 3 number_pixels 1 sub { pixels exch color_packet putinterval } for
+ pixels 0 number_pixels getinterval
+} bind def
+/DirectClassImage{
+ columns rows 8 [ columns 0 0 rows neg 0 rows ]
+ { DirectClassPacket } false 3 colorimage %}
+} bind def
+/GrayDirectClassPacket {
+ currentfile color_packet readhexstring pop pop
+ color_packet 0 get 0.299 mul
+ color_packet 1 get 0.587 mul add
+ color_packet 2 get 0.114 mul add
+ cvi
+ /gray_packet exch def
+ /number_pixels 1 def
+ 0 1 number_pixels 1 sub { pixels exch gray_packet put } for
+ pixels 0 number_pixels getinterval
+} bind def
+/GrayPseudoClassPacket {
+ currentfile byte readhexstring pop 0 get
+ /offset exch 3 mul def
+ /color_packet colormap offset 3 getinterval def
+ color_packet 0 get 0.299 mul
+ color_packet 1 get 0.587 mul add
+ color_packet 2 get 0.114 mul add cvi
+ /gray_packet exch def
+ /number_pixels 1 def
+ 0 1 number_pixels 1 sub { pixels exch gray_packet put } for
+ pixels 0 number_pixels getinterval
+} bind def
+/PseudoClassPacket{
+ currentfile byte readhexstring pop 0 get
+ /offset exch 3 mul def
+ /color_packet colormap offset 3 getinterval def
+ /number_pixels 3 def
+ 0 3 number_pixels 1 sub { pixels exch color_packet putinterval } for
+ pixels 0 number_pixels getinterval
+} bind def
+/PseudoClassImage{
+ currentfile buffer readline pop
+ token pop /class exch def pop
+ class 0 gt {
+ currentfile buffer readline pop
+ token pop /depth exch def pop
+ /grays columns 8 add depth sub depth mul 8 idiv string def
+ columns rows depth
+ [ columns 0 0 rows neg 0 rows ]
+ { currentfile grays readhexstring pop } image
+ }{
+ currentfile buffer readline pop
+ token pop /colors exch def pop
+ /colors colors 3 mul def
+ /colormap colors string def
+ currentfile colormap readhexstring pop pop
+ columns rows 8 [ columns 0 0 rows neg 0 rows ]
+ { PseudoClassPacket } false 3 colorimage
+ } ifelse
+} bind def
+/DisplayImage {
+ gsave
+ /buffer 512 string def
+ /byte 1 string def
+ /color_packet 3 string def
+ /pixels 768 string def
+ currentfile buffer readline pop
+ token pop /x exch def
+ token pop /y exch def pop
+ x y translate
+ currentfile buffer readline pop
+ token pop /x exch def
+ token pop /y exch def pop
+ currentfile buffer readline pop
+ token pop /pointsize exch def pop
+ x y scale
+ currentfile buffer readline pop
+ token pop /columns exch def
+ token pop /rows exch def pop
+ currentfile buffer readline pop
+ token pop /class exch def pop
+ currentfile buffer readline pop
+ token pop /compression exch def pop
+ class 0 gt { PseudoClassImage } { DirectClassImage } ifelse
+ grestore
+} bind def
+%%EndProlog
+%%Page: 1 1
+]])
+ outFile:write("%%PageBoundingBox: 0 0 "..res[1].." "..res[2].."\n")
+ outFile:write([[userdict begin
+DisplayImage
+0 0
+]])
+ outFile:write(res[1].." "..res[2].."\n")
+ outFile:write("12\n")
+ outFile:write(res[1].." "..res[2].."\n")
+ outFile:write([[0
+0
+]])
+ local i = 0
+ for row = 1, res[2] do -- alle Zeilen
+ for col = 1, res[1] do -- alle Spalten
+ for k = 1,3 do
+ if data[row][col][k] ~= data[row][col][k] then -- check for nan
+ outFile:write("FF")
+ else
+ local num = data[row][col][k]
+ if num < 16 then
+ hex = string.format("0%X", num)
+ else
+ hex = string.format("%X", num)
+ end
+ outFile:write(hex)
+ end
+ i = i + 1
+ if i == 39 then
+ outFile:write("\n") -- neue Zeile
+ i = 0
+ end
+ end
+ end
+ end
+ outFile:write("\n") -- neue Zeile
+ outFile:write([[end
+%%PageTrailer
+%%Trailer
+%%EOF
+]])
+ outFile:close() -- Datei schließen
+ --os.execute("pnmtopng apfel.ppm >"..fileName..".png") -- ppm -> png Format
+end
+
+function write_data(name,data,res) -- only valid for writing ppm files
+ print("Lua: writing data file "..name.." ...")
+-- print(data)
+ outFile = io.open(name,"w+") -- Dateiname
+ outFile:write("P3 ") -- Grafictype R G B
+ outFile:write(res[1].." "..res[2].." ") -- Anzahl Pixel: Breite x Höhe (cols x rows)
+ outFile:write("255\n") -- Höchster Zahlenwert (0..255)
+ for row = 1, res[2] do -- alle Zeilen
+ for col = 1, res[1] do -- alle Spalten
+ for k = 1,3 do
+ if data[row][col][k] ~= data[row][col][k] then -- check for nan
+ outFile:write("255 ")
+ else
+ outFile:write(data[row][col][k].." " )
+ end
+ end
+ end
+ outFile:write("\n") -- neue Zeile
+ end
+ outFile:close() -- Datei schließen
+ --os.execute("pnmtopng apfel.ppm >"..fileName..".png") -- ppm -> png Format
+end
+
+function plot(fString, domain, res, funcName, hsvrgb, bgColor, invers)
+ local left = domain[1]
+ local right = domain[2]
+ local bottom = domain[3]
+ local top = domain[4]
+ local dx = (right-left)/res[1]
+ local dy = (top-bottom)/res[2]
+ local img = {} -- mxn-Matrix (rows x colums) img[row][col]
+ for row = 1,res[2] do
+ img[row] = {}
+ for col = 1,res[1] do
+ img[row][col] = 0
+ end
+ end
+ for row = 1, res[2] do
+ y = top-dy*row
+ for col = 1,res[1] do
+-- print(j,i)
+ x = left+dx*col
+ z = complex(x, y)
+ if funcName then
+ fz = fString(z) -- use func number from external file
+ else
+ fz = load("return "..fString)() -- for example: cmath.cos(z)/cmath.sin(z^4-1)
+ end
+ color = my_color_scheme(fz,hsvrgb)
+ if bgColor == "true" then
+ if color[1] + color[2] + color[3] == 0 then
+ color = { 255, 255, 255 }
+ end
+ elseif invers == "true" then
+ for c=1,#color do
+ color[c] = math.abs(color[c]-255)
+ end
+ end
+-- print(x,y,color[1],color[2],color[3])
+ img[row][col] = color
+ end
+ end
+ return img
+end
+
+--[[
+ f: function as string if funcName is False
+ as funcName from external file if funcName is TRUE
+ Domain: xMin,xMax,yMin,yMax
+ Resolution: (points per Interval) xRes,yRes
+ funcName: true/false (see f)
+]]
+function createData(f,Domain,Resolution,funcName,hsvrgb,bgColor,invers)
+ if funcName == "" then
+ img = plot(f,Domain,Resolution,false,hsvrgb,bgColor,invers)
+ else
+ img = plot(load("return "..funcName)(),Domain,Resolution,true,hsvrgb,bgColor,invers)
+ end
+-- write_data("domain.ppm",img,Resolution)
+ write_eps_data("domain.eps",img,Resolution)
+end
+