我正在尝试适应这一点后肩突产生器适合给定的对列表宏.为此我循环遍历列表成对并确定所有点及其坐标之间的最大x
和距离。然后,我使用给定的和y
对 patatoid 生成器并将其移到最低坐标处以适应(几乎)所有点。width
height
def drawlistofpoints(suffix p) =
numeric i ; i := 0 ;
forever:
if known p[i]:
drawdot p[i] withpen pencircle scaled 3pt ;
i := i+1 ;
fi ;
exitif unknown p[i] ;
endfor ;
enddef ;
vardef patatoid(expr w,h,x,y) =
hide(
numeric i,maxi,maxd ; i:=0; maxd := 0 ;
numeric dist[] ;
pair tmpp[] ;
path sq, p ;
sq := unitsquare xyscaled (w,h) shifted (x, y) ;
for i = 0 upto 3:
tmpp[i] := point (i + uniformdeviate(1)) of sq ;
endfor ;
tmpp[4] := tmpp[0] ;
for i= 0 upto 3 :
dist[i] := abs(tmpp[i+1] - tmpp[i]) ;
if (dist[i] > maxd) :
maxd := dist[i] ;
maxi := i ;
fi ;
endfor ;
p := for i = 0 upto maxi : tmpp[i] .. endfor (uniformdeviate(1))[tmpp[maxi],tmpp[maxi+1]] for i = maxi + 1 upto 3: .. tmpp[i] endfor .. cycle ;
)
p
enddef ;
def drawset(suffix p)=
numeric i,w,h,lx,hx,ly,hy; i:=0; w:=0; h:=0; lx:=0; hx:=0; ly:=0; hy:=0;
numeric offset ; offset = 2cm ;
forever:
if known p[i]: % this is a naive approach
if (xpart p[i]) < lx: lx := (xpart p[i]); fi
if (xpart p[i]) > hx: hx := (xpart p[i]); fi
if (ypart p[i]) < ly: ly := (ypart p[i]); fi
if (ypart p[i]) > hy: hy := (ypart p[i]); fi
i:=i+1;
fi
exitif unknown p[i];
endfor ;
hx := hx+offset ; lx := lx-offset ; hy := hy+offset ; ly := ly-offset ;
w := abs(hx - lx) ; h := abs(hy - ly) ;
draw patatoid(w,h,lx,ly) withpen pencircle scaled 1pt ;
drawlistofpoints(p) ;
enddef ;
然而,如果一个点有“不寻常”的坐标,并且没有与其他点挤在一起,它就会在颈状突之外结束:
\startTEXpage
\startMPcode
pair a,b,c,d,e,f, g,h;
a := (0.5cm,0.75cm) ; b := (1.5cm,0.75cm) ; c := (2.5cm,0.75cm) ;
d := (0.5cm,2.25cm) ; e := (1.5cm,2.25cm) ; f := (2.5cm,2.25cm) ;
g := (2.25cm,4.5cm) ; h := (-1.5cm,-0.75cm) ;
pair points[];
points[0] := a ;
points[1] := b ;
points[2] := c ;
points[3] := d ;
points[4] := e ;
points[5] := f ;
points[6] := g ;
points[7] := h ;
drawset(points) ;
\stopMPcode
\stopTEXpage
我怎样才能确保它们全部适合?
答案1
这是一个不同的实现。
这被包裹在内luamplib
,因此用 进行编译lualatex
,或使其适应您的 Context 环境。
\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\begin{mplibcode}
beginfig(1);
pair p[];
for i=1 upto 10:
p[i] = 21(normaldeviate, normaldeviate);
endfor
picture dots; dots = image(
numeric i; i = 0;
forever:
exitif not known p[incr i];
draw p[i] withpen pencircle scaled 3;
endfor);
pair o; o = center dots;
path spud;
spud = for i=1/4 step 1/2 until 4:
(5/4 + uniformdeviate 1/2)[o, point i of bbox dots] ..
endfor cycle;
fill spud withcolor 1/256(239, 234, 181);
draw spud;
draw dots;
endfig;
\end{mplibcode}
\end{document}
笔记
我的方法是
在随机位置捕获 10 个点,如 p1、p2、p3 等
将所有点的绘图保存为
<picture>
变量然后使用中介语法绕着图片的边界框找到一个随机距离的点超过bbox。表达式
(5/4 + uniformdeviate 1/2)
产生一个介于 1.25 和 1.75 之间的随机数,并且由于o
定义为center
所有点的,1.5[o, point i of bbox dots]
因此产生一个点必须超出边界框。巧妙之处在于从点 1/4 开始,每次步进 1/2,这样我们就可以避开角落;这使得随机形状更像土豆。
1/256(239, 234, 181)
我在网上搜索找到了土豆颜色。
其他一些语法要点:
如果
i
是数字,则将incr i
就地增加它。还有decr i
执行相反操作的。中的实现plain.mp
非常巧妙:% special operators vardef incr suffix $ = $:=$+1; $ enddef; vardef decr suffix $ = $:=$-1; $ enddef;
在 Metapost 中(与 Metafont 不同)
drawdot <pair>
完全等同于draw <pair>
。
更多细节
这几行字里行间发生了什么事?
path spud;
spud = for i=1/4 step 1/2 until 4:
(5/4 + uniformdeviate 1/2)[o, point i of bbox dots] ..
endfor cycle;
此循环生成土豆形状的轮廓路径。(“spud” 一词是英国俚语,意为土豆。)这是一个内联循环;Metapost 在定义过程中扩展了循环,因此它扩展为:
spud = (1.25 + uniformdeviate 0.5)[o, point 0.25 of bbox dots] ..
(1.25 + uniformdeviate 0.5)[o, point 0.75 of bbox dots] ..
(1.25 + uniformdeviate 0.5)[o, point 1.25 of bbox dots] ..
(1.25 + uniformdeviate 0.5)[o, point 1.75 of bbox dots] ..
(1.25 + uniformdeviate 0.5)[o, point 2.25 of bbox dots] ..
(1.25 + uniformdeviate 0.5)[o, point 2.75 of bbox dots] ..
(1.25 + uniformdeviate 0.5)[o, point 3.25 of bbox dots] ..
(1.25 + uniformdeviate 0.5)[o, point 3.75 of bbox dots] .. cycle;
它会扩展成类似这样的内容(尽管显然uniformdeviate
每次的调用都会有所不同):
spud = (1.3399)[o, point 0.25 of bbox dots] ..
(1.7087)[o, point 0.75 of bbox dots] ..
(1.4047)[o, point 1.25 of bbox dots] ..
(1.4849)[o, point 1.75 of bbox dots] ..
(1.5348)[o, point 2.25 of bbox dots] ..
(1.3187)[o, point 2.75 of bbox dots] ..
(1.7404)[o, point 3.25 of bbox dots] ..
(1.3717)[o, point 3.75 of bbox dots] .. cycle;
中介语法的工作方式是,如果你把 放在 中,你将得到一个恰好位于和1/2[z0, z1]
之间 1/2 处的点,如果你把 放在 中,这个点将位于到 之间的3/4 处,依此类推。但如果分数是z0
z1
3/4[z0, z1]
z0
z1
更大大于 1 点将是超过 z1
,因此将在通过和的线上1.5[z0, z1]
超出“50%” ,因此由于位于点的中间,路径定义中的每个点都将成为超出bbox的点,它看起来像这样:z1
z0
z1
o
其中红色框是bbox
点,每个红色箭头指向路径上的一个点spud
。因此,左下角的点是边界框 0.25 点“超出”点的 33.99%,依此类推。巧妙之处在于避开角落。如果您看不到这一点,请尝试试验循环的起始值并观察会发生什么。