一位朋友展示了他们正在制作的被子图案。啊,我说,我可以轻松地在 Ti 中做到这一点钾Z 带pic
s。嗯,是也不是:当然可以做到;但不是那么容易。我有 pic
下面展示的图案,以及完全靠蛮力完成的成品图案。一定有一种方法可以更有效地做到这一点,并且可以推广到其他图案。
\documentclass{article}
\usepackage[papersize={5.5in,8.5in},margin=0.6in]{geometry}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric}
\tikzset{%
dartstyle/.style={kite,draw,kite vertex angles=60,inner sep=0.125in,outer sep=0pt,fill=#1},
pics/quiltdart/.style={%
code={%
\node[dartstyle=red](base) {};
\node[rotate=0,dartstyle=white,anchor=upper vertex] at (base.right vertex) {};
\node[rotate=0,dartstyle=white,anchor=upper vertex] at (base.left vertex) {};
\node[rotate=0,dartstyle=red,anchor=upper vertex] at (base.lower vertex) {};
}%
}%
}
\parindent0pt
\begin{document}
This was easy:
\tikz \pic {quiltdart};
\bigskip
This, not so much\dots
\tikz {\pic {quiltdart};
\pic[yshift=-0.51in,xshift=0.89in,rotate=-60,transform shape] {quiltdart};
\pic[yshift=-1.54in,xshift=0.89in,rotate=-120,transform shape] {quiltdart};
\pic[yshift=-2.05in,xshift=-0in,rotate=-180,transform shape] {quiltdart};
\pic[yshift=-1.54in,xshift=-0.89in,rotate=-240,transform shape] {quiltdart};
\pic[yshift=-0.51in,xshift=-0.89in,rotate=-300,transform shape] {quiltdart};
}
\end{document}
更新
首先,我要感谢那些回复我帖子的人:我学到了很多东西。因此,我把这篇文章作为更新而不是回答因为如果没有发人深省的答复,这一切都不可能实现,而我绝不会因此而减损这些答复。
这是我的方法。虽然它可能不是最高效的代码,但效果很好。另一方面,它很简单,易于维护/修改。
\documentclass[]{article}
\usepackage[rgb]{xcolor}
\usepackage{tikz}
\usetikzlibrary{positioning}
\usepackage[margin=1.4in,top=0.5in,left=0.75in]{geometry}
\NewDocumentCommand{\makeshape}{m}{%
\pgfmathsetmacro{\myhuei}{rnd}
\pgfmathsetmacro{\myhueii}{rnd}
\pgfmathsetmacro{\myhueiii}{rnd}
\definecolor{mycolori}{hsb}{\myhuei,1,1}
\definecolor{mycolorii}{hsb}{\myhueii,0.25,1}
\definecolor{mycoloriii}{hsb}{\myhueiii,1,1}
\pgfmathsetmacro{\lang}{180/#1}%
\pgfmathsetmacro{\bang}{90-\lang}%
\tikzset{%
pics/dart/.style={code={%
\draw[fill=mycolorii] (0,0) -- ++(90-\lang:2) --
++(180-\bang:2) -- ++(-90-\lang:2) -- cycle;
\draw[fill=mycolori](0,0) -- ++(90-\lang:1) -- ++(180 - \bang:1)coordinate(T) --
++(-90-\lang:1) -- cycle;
\draw[fill=mycoloriii](T) -- ++(90-\lang:1) -- ++(-180 - \bang:1) --
++(-90-\lang:1)-- cycle;
}%
},%
}%
\begin{tikzpicture}[rotate=\lang,scale=0.5]%% both rotate and scale can be altered to suit
\foreach \i [count=\ii from 0] in {1,...,#1}
\path pic[rotate around={360/#1*\ii:(0,0)},transform shape]{dart};
\end{tikzpicture}
}
\parindent0pt
\begin{document}
\thispagestyle{empty}
\foreach \N in {4,5,...,18}{\makeshape{\N}}
\end{document}
答案1
\foreach
通过使用语句并将rotate
选项替换为,可以实现一定程度的改进rotate around
。
\documentclass{article}
\usepackage[papersize={5.5in,8.5in},margin=0.6in]{geometry}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric}
\tikzset{%
dartstyle/.style={kite,draw,kite vertex angles=60,inner sep=0.125in,outer sep=0pt,fill=#1},
pics/quiltdart/.style={%
code={%
\node[dartstyle=red](base) {};
\node[rotate=0,dartstyle=white,anchor=upper vertex] at (base.right vertex) {};
\node[rotate=0,dartstyle=white,anchor=upper vertex] at (base.left vertex) {};
\node[rotate=0,dartstyle=red,anchor=upper vertex]
at (base.lower vertex)(bottom dart){}; % <-----
}%
}%
}
\parindent0pt
\begin{document}
This was easy:
\tikz \pic {quiltdart};
\bigskip
What about this ???
\begin{tikzpicture}
\foreach \i in {0,60,...,300}{
\pic[rotate around={\i:(bottom dart.lower vertex)},
transform shape] {quiltdart};
}
\end{tikzpicture}
\end{document}
另一种解决方案通过修改图片代码,使得图片的原点对应于最低顶点:
\documentclass{article}
\usepackage[papersize={5.5in,8.5in},margin=0.6in]{geometry}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric}
\tikzset{%
dartstyle/.style={kite,draw,kite vertex angles=60,inner sep=0.125in,outer sep=0pt,fill=#1},
pics/quiltdart/.style={%
code={%
\node[dartstyle=red,anchor=lower vertex](base) {};
\node[dartstyle=white,anchor=left vertex] at (base.upper vertex) {};
\node[dartstyle=white,anchor=right vertex] at (base.upper vertex) {};
\node[dartstyle=red,anchor=lower vertex] at (base.upper vertex){};
}%
}%
}
\parindent0pt
\begin{document}
%This was easy:
%\tikz \pic {quiltdart};
%\bigskip
%This, not so much\dots
\begin{tikzpicture}
% first copy
\foreach \i in {0,60,...,300}{
\pic[rotate =\i,transform shape] {quiltdart};
}
% second copy
\foreach \i in {0,60,...,300}{
\pic[rotate =\i,transform shape] at(0,8){quiltdart};
}
\end{tikzpicture}
\end{document}
答案2
只用path
,不用pics
或nodes
\documentclass{article}
\usepackage[papersize={5.5in,8.5in},margin=0.6in]{geometry}
\usepackage{tikz}
\newcommand{\mydart}[1][]{
\filldraw[black, fill=red, even odd rule,#1] (0,0)--++(60:1)--++(120:1)--++(240:1)--cycle (60:.5)--++(60:.5)--++(120:.5)--++(240:1)--++(120:.5)--++(60:.5)--cycle
}
\begin{document}
This was easy:
\tikz \mydart;
\bigskip
What about this ???
\begin{tikzpicture}
\foreach \i in {0,60,...,300}{
\mydart[rotate around={\i:(0,0)}];
}
\end{tikzpicture}
or this ???
\begin{tikzpicture}
\foreach \i in {0,60,...,300}{
\mydart[shift={(\i:1)}, rotate=\i];
}
\end{tikzpicture}
\end{document}
答案3
这是另一种方法,改变pic
。在我的画中pic
,我画了四个正方形,但我改变了轴来“变形”它们。
像这样:
\documentclass[border=2mm,tikz]{standalone}
\definecolor{color0}{HTML}{FFFFFF} % white
\definecolor{color1}{HTML}{FF0000} % red
\tikzset
{%
pics/quiltdart/.style={
code={%
\pgfmathsetmacro\y{sin(60)}
\begin{scope}[x={(0.5 cm,\y cm)}, y={(-0.5 cm,\y cm)}]
\foreach\i in {0,1} \foreach\j in {0,1}
{
\pgfmathtruncatemacro\c{Mod(\i+\j+1,2)}
\draw[fill=color\c] (\i,\j) -- (\i,\j+1) -- (\i+1,\j+1) -- (\i+1,\j) -- cycle;
}
\end{scope}
}},
}
\begin{document}
\begin{tikzpicture}[line join=round]
\foreach\a in {0,60,...,300}
\pic[rotate=\a] {quiltdart};
\end{tikzpicture}
\end{document}
答案4
新的解决方案
\documentclass[border=5mm]{standalone}
\usepackage[rgb]{xcolor}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\tikzset{quiltdart/.pic={%
\def\n{#1} % the number of quiltdart
% random colors from OP
\pgfmathsetmacro{\myhuei}{rnd}
\pgfmathsetmacro{\myhueii}{rnd}
\pgfmathsetmacro{\myhueiii}{rnd}
\definecolor{mycolori}{hsb}{\myhuei,1,1}
\definecolor{mycolorii}{hsb}{\myhueii,0.25,1}
\definecolor{mycoloriii}{hsb}{\myhueiii,1,1}
\def\basicdart{(0,0)--(90-360/\n:1)--+(0,1)--(0,1)--cycle}
\foreach \i in {0,...,\n}{
\draw[fill=mycoloriii,rotate=\i*360/\n,shift={(90-360/\n:1)},shift={(0,1)}] \basicdart;
\draw[fill=mycolori,rotate=\i*360/\n] \basicdart;
\draw[fill=mycolorii,rotate=\i*360/\n,shift={(0,1)}] \basicdart;
\draw[fill=mycolorii,rotate=\i*360/\n,shift={(0,1)},xscale=-1] \basicdart;
}
}}
\newcounter{myquilt}
\setcounter{myquilt}{2}
\foreach \j in {1,...,5}
\foreach \i in {1,...,8}
{\stepcounter{myquilt}
\path (6*\i,-6*\j) pic[scale=.6]{quiltdart=\themyquilt}
% +(-90:2.6) node{$n=$ \themyquilt} % show the number of quiltdart
;
}
\end{tikzpicture}
\end{document}
旧解决方案
我猜关键问题是居中/不居中pic
,既不居中pic of nodes
也不居中rotate
。这变成了非常有趣的情况:
pic
是否以原点为中心 (名称dart
)pic
的pic
s(名称quiltdart
)。
我为 s 的参数添加了默认值pic
。使用选项[rotate,shift]
代替[rotate around]
。我希望代码和图片是不言自明的。
\documentclass[border=5mm,tikz]{standalone}
% Multi-parameters pic with default
\tikzset{
pics/dart/.style args={#1 and #2}{code={%
\draw[fill=#1] (-120:1)--(60:1)--([turn]60:1)--(120:1)--(-60:1)--([turn]-60:1)--cycle;
\draw[fill=#2] (-120:1)--(60:1)--(0:1)--(-60:1)--(120:1)--(180:1)--cycle;
}},
pics/dart/.default={red and white}
}
% Multi-parameters pic of pics with default
\tikzset{pics/quiltdart/.style args={#1 and #2}{code={%
\foreach \i in {0,...,5}
\path (0,0) pic[rotate=60*\i,shift={(0,-sqrt(3))}]{dart={#1 and #2}};
}},
pics/quiltdart/.default={red and white}
}
\begin{document}
\begin{tikzpicture}
\path
(0,0) pic{dart} node[above=2.5cm,scale=2]{\verb|\pic{dart}|}
(18,0) pic{dart={magenta and cyan}} node[above=2.5cm,scale=2]{\verb|\pic{dart={magenta and cyan}}|};
\foreach \i in {0,...,5}
\path (0,-10) pic[rotate=60*\i,shift={(0,-sqrt(3))}]{dart};
\path (0,-10) node[above=3.5cm,scale=2,align=center]{Good\\
\verb|\foreach \i in {0,...,5}|\\
\verb|\pic[rotate=60*\i,shift={(0,-sqrt(3))}]{dart}|};
\path
(18,-10) pic{quiltdart={magenta and cyan}} node[above=3.5cm,scale=2,align=center]{Better\\
\verb|\pic{quiltdart={magenta and cyan}}|};
\end{tikzpicture}
\end{document}
被子装饰的一些示例
- 平面的平铺
\begin{tikzpicture}
\foreach \i in {0,...,5}
\foreach \j in {0,...,4}
\path (5*\i,-5*\j) pic{quiltdart};
\end{tikzpicture}
- 绿色被子
\begin{tikzpicture}
\foreach \i in {0,...,5}
\foreach \j in {0,...,4}
\path (8*\i,-8*\j) pic{quiltdart={green and white}};
\end{tikzpicture}
更新 Asymptote 版本 pic
spic
可以从 TikZ 转换为 Asymptote。
unitsize(1cm);
// creating dart
picture dart;
unitsize(dart,1cm);
path p=dir(-120)--dir(60)--dir(0)--dir(-60)--dir(120)--dir(180)--cycle;
path q=dir(-120)--dir(60)--sqrt(3)*dir(90)--dir(120)--dir(-60)--sqrt(3)*dir(-90)--cycle;
filldraw(dart,p,pink,black);
filldraw(dart,q,purple,black);
// creating quiltdart from darts
picture quiltdart;
unitsize(quiltdart,1cm);
for(int i=0;i<6;++i)
add(quiltdart,rotate(i*60)*shift(0,-sqrt(3))*dart);
// Here is the quilt
for (int i=0;i<6;++i)
for (int j=0;j<3;++j)
add(shift(8*i,-8*j)*quiltdart);
shipout(bbox(1cm,invisible));
更新 2:一般情况n-point-star quiltdarts 的概括。有时,一般问题比特定问题更容易处理。这是我对 OP 新更新答案的情况的感受。
想法很简单,直接创建一个带参数的函数n
。共有 3 个类;每个类都由基本飞镖的旋转组成;中间类需要注意一点。
n=20 quiltdart(20,yellow,magenta,purple);
// http://asymptote.ualberta.ca/
unitsize(1cm);
// the basic dart
path dart(int n){
pair A=(0,0),D=(0,1),B=dir(90-360/n),C=B+D-A;
return A--B--C--D--cycle;
}
// the quiltdart of three classes
void quiltdart(int n, pen innerpen, pen middlepen, pen outerpen){
for(int i=0;i<n;++i){
transform rot=rotate(i*360/n);
path outerclass=rot*shift((0,1)+dir(90-360/n))*dart(n);
path middleclass1=rot*shift(0,1)*dart(n);
path middleclass2=rot*shift(0,1)*xscale(-1)*dart(n);
path innerclass=rot*dart(n);
filldraw(outerclass,outerpen,black);
filldraw(middleclass1,middlepen,black);
filldraw(middleclass2,middlepen,black);
filldraw(innerclass,innerpen,black);
}}
quiltdart(20,yellow,magenta,purple);
shipout(bbox(1cm,invisible));
n=4 quiltdart(4,yellow,orange,green);
n=50 quiltdart(50,yellow,green,red);
更新 3:TikZ 的通用解决方案n=45
是 TikZ/TeX 可以编译的最大数量,而不会引起烦恼并引发“尺寸太大”错误。
\documentclass[border=5mm,tikz]{standalone}
\begin{document}
\begin{tikzpicture}
\def\n{45}
\def\basicdart{(0,0)--(90-360/\n:1)--+(0,1)--(0,1)--cycle}
\foreach \i in {0,...,\n}{
\draw[fill=magenta,rotate=\i*360/\n,shift={(90-360/\n:1)},shift={(0,1)}] \basicdart;
\draw[fill=yellow,rotate=\i*360/\n] \basicdart;
\draw[fill=orange,rotate=\i*360/\n,shift={(0,1)}] \basicdart;
\draw[fill=orange,rotate=\i*360/\n,shift={(0,1)},xscale=-1] \basicdart;
}
\end{tikzpicture}
\end{document}