2

I'm trying to calculate things inside the \newcommand

\documentclass[tikz]{standalone}

\usepackage{tikz}

\def\spradius{1}
\newcommand*{\projectToSphere}[2]{%
        % calculate a reverse projection point of (#1, #2, 0) on the sphere centered at (0,0,\spradius) of \spradius (radius)
        \pgfmathsetmacro{\XYTwo}{(#1)^2 + (#2)^2}
        \pgfmathsetmacro{\zvalue}{(2 * \XYTwo) / (\XYTwo / \spradius + 4 * \spradius)}
        \pgfmathsetmacro{\xvalue}{(2 * \spradius - \zvalue) / (2 * \spradius) * #1}
        \pgfmathsetmacro{\yvalue}{(2 * \spradius - \zvalue) / (2 * \spradius) * #2}
        {\xvalue}, {\yvalue}, {\zvalue}
}%

\begin{document}

    \begin{tikzpicture}

        \draw[fill=green] (\projectToSphere{3}{4}) circle (0.5pt);
    \end{tikzpicture}
\end{document}

and I keep getting ! Incomplete \iffalse;

What I have tried:

  • moved \newcommand outside of tikzpicture
  • moved \newcommand outside the document
  • added * to the \newcommand
  • direct calculations work, but my actual calculations are more complex, so it will be difficult to have direct calculations inside.

Is it possible to make \pgfmathsetmacro or \pgfmathparse to work inside the \newcommand?

Edit: What am I trying to achieve What i ultimately want to draw

dEmigOd
  • 397

1 Answers1

2

\pgfmathparse and \pgfmathsetmacro work in \newcommand, it is just that tikz parses the coordinates in a way that is nice in most situations but not here. You can define a function but unfortunately you'd need to insert it component by component.

\documentclass[tikz]{standalone}
\def\spradius{1} %<- maybe not a good practice

\pgfmathdeclarefunction{projectToSphereX}{2}{%
\begingroup%
\pgfmathparse{{projectToSphere(#1,#2)}[0]}%
\pgfmathsmuggle\pgfmathresult\endgroup%
}%
\pgfmathdeclarefunction{projectToSphereY}{2}{%
\begingroup%
\pgfmathparse{{projectToSphere(#1,#2)}[1]}%
\pgfmathsmuggle\pgfmathresult\endgroup%
}%
\pgfmathdeclarefunction{projectToSphereZ}{2}{%
\begingroup%
\pgfmathparse{{projectToSphere(#1,#2)}[2]}%
\pgfmathsmuggle\pgfmathresult\endgroup%
}%


\pgfmathdeclarefunction{projectToSphere}{2}{%
\begingroup%
\pgfmathsetmacro{\XYTwo}{(#1)^2 + (#2)^2}%
\pgfmathsetmacro{\zvalue}{(2 * \XYTwo) / (\XYTwo / \spradius + 4 * \spradius)}%
\pgfmathsetmacro{\xvalue}{(2 * \spradius - \zvalue) / (2 * \spradius) * #1}%
\pgfmathsetmacro{\yvalue}{(2 * \spradius - \zvalue) / (2 * \spradius) * #2}%
\edef\pgfmathresult{\xvalue,\yvalue,\zvalue}%
\pgfmathsmuggle\pgfmathresult\endgroup%
}%


\begin{document}
    \pgfmathparse{projectToSphere(3,4)}
        \begin{tikzpicture}
    \draw[fill=green] 
        ({projectToSphereX(3,4)},{projectToSphereY(3,4)},{projectToSphereZ(3,4)}) 
        circle[radius=0.5pt];
    \end{tikzpicture}
\end{document}

It appears to me that you may be looking for nonlinear transformations.

\documentclass[tikz,border=3mm]{standalone}
\usepackage{tikz-3dplot}
\usepgflibrary{fpu}
\usepgfmodule{nonlineartransformations} 
\newcommand{\PgfmathsetmacroFPU}[2]{\begingroup% https://tex.stackexchange.com/a/503835
\pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed}%
\pgfmathsetmacro{#1}{#2}%
\pgfmathsmuggle#1\endgroup}%
\makeatletter
\def\fancyspheretransformation{% similar to the pgfmanual section 103.4.2
\PgfmathsetmacroFPU{\XYTwo}{\pgf@x*\pgf@x+\pgf@y*\pgf@y}%
\PgfmathsetmacroFPU{\zvalue}{-(2*\XYTwo)/(\XYTwo/\spradius+4*\spradius)}%
\PgfmathsetmacroFPU{\xvalue}{(2*\spradius-\zvalue)/(2*\spradius)*\pgf@x}%
\PgfmathsetmacroFPU{\yvalue}{(2*\spradius-\zvalue)/(2*\spradius)*\pgf@y}%
\PgfmathsetmacroFPU{\myx}{cos(\tdplotmainphi)*\xvalue+sin(\tdplotmainphi)*\yvalue}%
\PgfmathsetmacroFPU{\myy}{-cos(\tdplotmaintheta)*sin(\tdplotmainphi)*\xvalue+cos(\tdplotmaintheta)*cos(\tdplotmainphi)*\yvalue-sin(\tdplotmaintheta)*\zvalue}%
\pgf@y=\myy pt% \typeout{z=\zvalue,x=\xvalue,y=\yvalue}%
\pgf@x=\myx pt%
} 
\makeatother
\begin{document}
\begin{tikzpicture}
 \def\spradius{4cm} %<- maybe not a good practice
 \tdplotsetmaincoords{70}{110}
 \begin{scope}[tdplot_main_coords,canvas is xy plane at z=-2]
  \foreach \Color [count=\X starting from -3] in {blue,cyan,green,yellow,orange,red}
   {\foreach \Y in {-3,...,2}
   {\draw[fill=\Color] (\X,\Y) rectangle (\X+1,\Y+1);}}
 \end{scope}
 \begin{scope}[transform shape nonlinear=true,]
  \pgftransformnonlinear{\fancyspheretransformation}
  \foreach \Color [count=\X starting from -3] in {blue,cyan,green,yellow,orange,red}
   {\foreach \Y in {-3,...,2}
   {\draw[fill=\Color] (\X,\Y) rectangle (\X+1,\Y+1);}}
 \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

  • There are two problems with the solution. It does work with raw numbers, but passing other \pgfmathsettedmacro-s does not. And it is unfortunately roughly as fast as fpeval solution of @egreg (from yesterday) – dEmigOd Feb 05 '20 at 07:57
  • @dEmigOd I do not understand what you mean by "but passing other \pgfmathsettedmacros does not". Also, you may want to explain what you really want to do. –  Feb 05 '20 at 11:55
  • I want to back-project an object (colored square) to the sphere. As I didn't find a ready package, I'm calculating position of many small squares and color them appropriately. (I will add the image of what I already have to the post) – dEmigOd Feb 05 '20 at 12:26
  • @dEmigOd Like this? Or an arbitrary object like this? Then see here. –  Feb 05 '20 at 12:33
  • Added an image, it is not an easy task :-( – dEmigOd Feb 05 '20 at 12:46
  • And yes, I saw the first post - I'm also working on animating mobius transformations – dEmigOd Feb 05 '20 at 12:48
  • @dEmigOd Why can't you use https://tex.stackexchange.com/a/199715 for that? –  Feb 05 '20 at 12:58
  • @dEmigOd I added something using nonlinear transformations to map a grid on the sphere using your map. –  Feb 06 '20 at 07:53