问题是获取任意数量点的重心。如果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}
处理参数更好。TeX
lua
问题更新:不幸的是,我犯了一个错误,因为要使用词缀,您必须从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}
处理参数更好。TeX
lua
使用 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
),这些循环速度更快。
我将提供一个不同的barycenter
Lua 函数,它不使用任何复数,而只返回两个将直接转发给 PGF 的值。
使用\tikz@parse@node
确保在访问坐标(甚至可能是节点)时,必要时使用name prefix
和。定义新坐标时name suffix
也是如此。\tikz@pp@name
在下面的代码中,我#2'
通过barycentric cs
(红色十字)和#2
Lua(圆圈)进行了定义。
对于通过 实现的 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}