将多个参数从宏传递给lua函数

将多个参数从宏传递给lua函数

问题是获取任意数量点的重心。如果lua不使用,则TikZ使用,否则使用lua。(抱歉,问题很长)

仅使用“TikZ”的代码如下:

\documentclass{article}
\usepackage{tikz}

\def\barycenter(#1)#2{%
\path[coordinate]  (barycentric cs:#1) coordinate (#2);}
\begin{document}     
\begin{tikzpicture}
\coordinate (A) at (1,0);
\coordinate (B) at (5,-1);
\coordinate (C) at (2,5);
\barycenter(A=1,B=1,C=1){G} % #1 the list A=1,B=1,C=1 #2 G barycenter
\draw (A) -- (B) -- (C) --cycle;
\node[circle, inner sep = 0pt,fill=lightgray,
  draw=black,minimum size =4pt] at (G) {};
\end{tikzpicture}
\end{document}

对于重心坐标系,⟨坐标规范⟩ 应为以逗号分隔的表达式列表,形式为 ⟨节点名称⟩=⟨数字⟩。请注意(目前)列表在 ⟨节点名称⟩ 之前或之后不应包含任何空格(与普通的键值对不同)。

不调用lua的情况下,代码如下:(有些解释需要说明,在代码后面)

\documentclass[landscape]{article}
\usepackage{tikz,luacode}
\directlua{bary = require("bary")}
\begin{document}    
\begin{tikzpicture}
\luadirect{
require "complex"
z = {}
z.A = complex.new (1,0)
z.B = complex.new (5,-1)
z.C = complex.new (2,5)
z.G = barycenter ({z.A,1},{z.B,1},{z.C,1})
for K,V in pairs(z) do
    tex.print("\\coordinate ("..K..") at ("..V.re..","..V.im..") ;")
end
}
\draw (A) -- (B) -- (C) --cycle;
\node[circle, inner sep = 0pt,fill=lightgray,
  draw=black,minimum size =4pt] at (G) {};
\end{tikzpicture}    
\end{document}

重心函数位于bary.lua以下文件中

function barycenter (...)
    local cp = table.pack(...)
    local i
    local sum = 0
    local weight=0
    for i=1,cp.n do
        sum = sum + cp[i][1]*cp[i][2]
        weight = weight + cp[i][2]
    end
  return sum/weight
end

该函数基于复数计算,您还必须complex.lua在此处下载库https://gist.github.com/MihailJP/3500284

z ={}创建表,键是未来“节点”的点的名称,值显然是点的坐标。

z.C = complex.new (2,5)将点C与其词缀 联系起来z.C = 2+5i

重心通过以下方式获得z.G = barycenter ({z.A,1},{z.B,1},{z.C,1})

问题:如何修改下一个宏来调用 barycenter 函数。

\def\barycenter(#1)#2{%
\path[coordinate]  (barycentric cs:#1) coordinate (#2);
% How to replace the previous line to call the barycenter function of lua ?
} 

问题是如何从A=1,B=1,C=1知道它可以是两点、三点甚至四点!我不知道在还是 在 中{A,1},{B,1},{C,1}处理参数更好。TeXlua

问题更新:不幸的是,我犯了一个错误,因为要使用词缀,您必须从A=1,B=1,C=1{z.A,1},{z.B,1},{z.C,1}而不是 到{A,1},{B,1},{C,1}

在此处输入图片描述

答案1

问题是如何从A=1,B=1,C=1知道它可以是两点、三点甚至四点!我不知道在还是 在 中{A,1},{B,1},{C,1}处理参数更好。TeXlua

使用 TeX 很容易实现。这是一个用户级解决方案,仅使用 TikZ 已提供的功能。

PGFKeys 和 PGFFor 提供了.list循环列表(通过\foreach)的处理程序,但不对其主体进行分组。

对于列表中的每个元素,<node>=<weight>该元素{<x>,<y>,<weight>}都将被添加到一个列表中,该列表只是一个值键(此处/utils/tempa),稍后可以完全扩展。

第一个元素将以不同的方式处理,因为我们不希望,在开始时出现。

不幸的是,PGFKeys 在过程中丢失了一些括号,这使得在初始化值时必须使用四对括号。不过,我们可以回退到宏\pgfkeyssetvalue(这只是一个幻想\def)。


使用 PGFkeys(主要\pgfkeysaddvalue)可避免使用高级包(如etoolbox\appto)或l3clist\clist_put_right:Nn),而使用 PGFFor(通过.list)可避免使用低级循环(如\pgfutil@for或 LaTeX 的\@for),这些循环速度更快。


我将提供一个不同的barycenterLua 函数,它不使用任何复数,而只返回两个将直接转发给 PGF 的值。

使用\tikz@parse@node确保在访问坐标(甚至可能是节点)时,必要时使用name prefix和。定义新坐标时name suffix也是如此。\tikz@pp@name

在下面的代码中,我#2'通过barycentric cs(红色十字)和#2Lua(圆圈)进行了定义。


对于通过 实现的 Lua 解决方案.list, 之前的空格,是允许的,但是在 之前的空格=仍然会引发错误 – 就像它们对 TikZ 自己的 所做的那样barycentric cs


\tikz@baryget与主代码中的定义相同,并添加以下两个内容:

\pgfqkeys{/tikz/cs/@Lua@bary}{
  .unknown/.code=%
    \let\tikz@key\pgfkeyscurrentname
    \pgfkeysalso{/tikz/cs/@Lua@bary/@@add/.expanded={\tikz@key}{#1}},
  @@initial/.style={
    @@add/.code 2 args=%
      \tikz@parse@node\tikz@baryget(##1)%
      \pgfkeyssetevalue{/tikz/cs/@Lua@bary/@@temp}{{\tikz@temp,##2}}%
      \pgfkeysalso{/tikz/cs/@Lua@bary/@@add/.code 2 args=%
        \tikz@parse@node\tikz@baryget(####1)%
        \edef\tikz@temp{\noexpand\pgfkeysaddvalue
          {/tikz/cs/@Lua@bary/@@temp}{,{\tikz@temp,####2}}}%
        \tikz@temp},
  }
}
\tikzdeclarecoordinatesystem{Lua barycentric}{%
  \pgfkeys{/tikz/cs/@Lua@bary/.cd,@@initial,#1}%
  \directlua{
    sumx, sumy = barycenter(\pgfkeysvalueof{/utils/bary from lua/to lua})
    tex.print("\\pgfqpoint{"..sumx.."pt}{"..sumy.."pt}")
  }%
}

坐标规范如下

\draw[green] (Lua barycentric cs: A = 1, B = 1, C = 1) circle[radius=4pt];

无需处理任何空格(因为 PGFKeys 解析列表)并且允许即时指定坐标而无需额外的宏。

它也不再使用 PGFFor。(两者的结合是可能的。)

代码

% !TeX TS-program = lualatex
\documentclass[tikz]{standalone}
\directlua{
function barycenter (...)
  local cp = table.pack(...)
  local i
  local sumx = 0
  local sumy = 0
  local weight = 0
  for i=1,cp.n do
      sumx = sumx + cp[i][1]*cp[i][3]
      sumy = sumy + cp[i][2]*cp[i][3]
      weight = weight + cp[i][3]
  end
  return sumx/weight, sumy/weight
end
}
\makeatletter
\def\tikz@baryget#1{%
  \pgf@process{#1}%
  \edef\tikz@temp{\pgf@sys@tonumber\pgf@x,\pgf@sys@tonumber\pgf@y}}%
\pgfkeys{
  /utils/bary from lua/.style args={#1,#2}{
    /utils/temp/.code args={##1=##2}{%
      \tikz@parse@node\tikz@baryget(##1)%
      \pgfkeyssetevalue{/utils/bary from lua/to lua}{{\tikz@temp,##2}}},
    /utils/temp={#1},
    /utils/temp/.code args={##1=##2}{%
      \tikz@parse@node\tikz@baryget(##1)%
      \edef\tikz@temp{\noexpand\pgfkeysaddvalue
        {/utils/bary from lua/to lua}{}{,{\tikz@temp,##2}}}%
      \tikz@temp},
    /utils/temp/.list={#2}}}
\def\barycenter(#1)#2{%
  \coordinate (#2') at (barycentric cs:#1);
  \pgfutil@in@{,}{#1}% just in case
  \ifpgfutil@in@
    \pgfkeys{/utils/bary from lua={#1}}%
  \else
    \pgfkeys{/utils/bary from lua={#1,}}% \foreach ignores empty
  \fi
  \directlua{
    sumx, sumy = barycenter(\pgfkeysvalueof{/utils/bary from lua/to lua})
    tex.print("\\pgfcoordinate{\\csname tikz@pp@name\\endcsname{#2}}
                              {\\pgfqpoint{"..sumx.."pt}{"..sumy.."pt}}")
  }%
}
\makeatother
\begin{document}
\begin{tikzpicture}
\coordinate (A) at (1,0);
\coordinate (B) at (5,-1);
\coordinate (C) at (2,5);
\barycenter(A=1,B=1,C=1){G}
\draw (A) -- (B) -- (C) --cycle;
\node[circle, inner sep = 0pt, fill=lightgray,
  draw=black, minimum size =4pt] at (G) {};
\draw[red] (G') +(north west:2pt) -- +(south east:2pt)
                +(north east:2pt) -- +(south west:2pt);
\end{tikzpicture}
\end{document}

输出

在此处输入图片描述

相关内容