diff options
author | Norbert Preining <norbert@preining.info> | 2024-08-22 03:03:13 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2024-08-22 03:03:13 +0000 |
commit | b705e74a380bef7cb2ca827bff29f28062cbdbe2 (patch) | |
tree | 7c177db5522f64d976c77f47ad1bfcfc9af27668 /macros/luatex | |
parent | 53ed061f98728598170f14eeb5476b2fed9499f8 (diff) |
CTAN sync 202408220303
Diffstat (limited to 'macros/luatex')
-rw-r--r-- | macros/luatex/latex/domaincoloring/Changes | 1 | ||||
-rw-r--r-- | macros/luatex/latex/domaincoloring/README.md | 10 | ||||
-rw-r--r-- | macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.bib | 27 | ||||
-rw-r--r-- | macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.pdf | bin | 0 -> 7132684 bytes | |||
-rw-r--r-- | macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.tex | 249 | ||||
-rw-r--r-- | macros/luatex/latex/domaincoloring/doc/hsv.png | bin | 0 -> 533343 bytes | |||
-rw-r--r-- | macros/luatex/latex/domaincoloring/latex/domaincoloring.sty | 71 | ||||
-rw-r--r-- | macros/luatex/latex/domaincoloring/lua/complex-numbers.lua | 357 | ||||
-rw-r--r-- | macros/luatex/latex/domaincoloring/lua/domaincoloring-functions.lua | 74 | ||||
-rw-r--r-- | macros/luatex/latex/domaincoloring/lua/domaincoloring.lua | 289 |
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 Binary files differnew file mode 100644 index 0000000000..19e3b30033 --- /dev/null +++ b/macros/luatex/latex/domaincoloring/doc/domaincoloring-doc.pdf 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 Binary files differnew file mode 100644 index 0000000000..4595b284ab --- /dev/null +++ b/macros/luatex/latex/domaincoloring/doc/hsv.png 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 + |