PS
# Traintracks.m4
#
https://tex.stackexchange.com/questions/729226/implementing-train-tracks-in-latex
gen_init
define(`robustcode_',1)
divert(-1)
########################################################################
`Default sizes'
define(`sectionlen',linewid)
define(`railgauge',(linewid/5))
define(`railthick',`1.5')
define(`buttlen',`(railthick bp__ * 3)')
define(`sleeperthick',`0.4')
define(`buttthick',`(sleeperthick*2)')
`straight(position,direction,keys)
keys: length=expr; (default sectionlen)
gauge=expr; (default railgauge)
tiecount=expr; (number of sleepers)
tie=attributes;
rail=attributes;'
define(`straight',`ifelse(`$1',,,move to `$1';) ifelse(`$2',,,`setdir_(`$2')')
pushkeys_(`$3',
`length:sectionlen:N; gauge:railgauge; rail::N; tiecount:3:; tie::N;')dnl
for straighti=1 to m4tiecount do {
{line from rvec_((straighti-1/2)*m4length/m4tiecount, m4gauge/2+buttlen/2) \
to rvec_((straighti-1/2)*m4length/m4tiecount,-m4gauge/2-buttlen/2) \
thick sleeperthick m4tie }}
{strail(m4gauge/2)}; {strail(-m4gauge/2)}; move to rvec_(m4length,0)dnl
popdef(`m4tie',`m4tiecount',`m4length',`m4gauge',`m4rail') ')
define(`strail',
`{line from rvec_(0,`$1') to rvec_(sectionlen,`$1') thick railthick m4rail
line from rvec_(0,-buttlen/2) to rvec_(0,buttlen/2) thick buttthick}
{line from rvec_(0,`$1'-buttlen/2) to rvec_(0,`$1'+buttlen/2) \
thick buttthick m4rail} ')
`curve(position,direction,L|R,keys)
keys: radius=expr; (default sectionlen*2)
gauge=expr; (default railgauge)
tiecount=expr; (number of sleepers)
tie=attributes;
rail=attributes;
Calls to robust rvec_r instead of rvec_ are for
use in pic loops'
define(`curve',`ifelse(`$1',,,move to `$1';) ifelse(`$2',,,`setdir_(`$2')')
pushkeys_(`$4',
`radius:sectionlen*2; gauge:railgauge; rail::N; tiecount:3:; tie::N;')dnl
pushdef(`m4pm',`ifelse(`$3',,+,`$3',L,+,-)')dnl
M4C: rvec_r(0,m4pm m4radius) # robust rvec
m4rs = rp_ang*rtod_-(m4pm 90); m4rf = m4rs m4pm 30
for curvei=1 to m4tiecount do {{ line \
from M4C+(Rect_(m4radius+m4gauge/2+buttlen/2,\
m4rs+(curvei-1/2)*(m4rf-m4rs)/m4tiecount))\
to M4C+(Rect_(m4radius-m4gauge/2-buttlen/2,\
m4rs+(curvei-1/2)*(m4rf-m4rs)/m4tiecount)) thick sleeperthick m4tie }}
move to M4C+(Rect_(m4radius,m4rs))
{crail(M4C,m4radius-(m4pm m4gauge/2), m4gauge/2,m4pm)}
{crail(M4C,m4radius+(m4pm m4gauge/2),-m4gauge/2,m4pm)}
move to M4C+(Rect_(m4radius,m4rf)); setdir_(rp_ang*rtod_ m4pm 30)
popdef(`m4tie',`m4tiecount',`m4rail',`m4gauge',`m4radius',`m4pm') ')
define(`crail', #`crail(center,rad,offset,+|-)'
`move to rvec_r(0,`$3'); crbuttf = buttlen/2/(`$2')
{arc ifelse(`$4',-,cw) to rvec_r((`$2')/2,`$4'((1-sqrt(3)/2)*(`$2'))) \
with .c at `$1' thick railthick m4rail
line from (-crbuttf between Here and `$1') \
to ( crbuttf between Here and `$1') thick buttthick}
{line from (-crbuttf between Here and `$1') \
to ( crbuttf between Here and `$1') thick buttthick} ')
########################################################################
divert(0)dnl
[ straight
{curve; curve(,,R); straight; curve(,,R); curve; straight}
for i=1 to 5 do { straight } ]
[ straight
for i=1 to 6 do { curve(,,R) }
straight
{T: Here
curve(,,R,rail=outlined "red"); curve(,,,rail=outlined "red")
straight
crad = sectionlen*2-(Here.y-T.y)
for i=1 to 6 do { curve(,,R,radius=crad) }
straight
define rgbpurp { rgbstring(0.5,0,1) }
{ curve(,,, rail=outlined rgbpurp); curve(,,R, rail=outlined rgbpurp)
for i=1 to 5 do { straight(,180) } }
for i=1 to 3 do { straight(,0) }
for i=1 to 6 do { curve(,,R,radius=crad) }
for i=1 to 3 do { straight } }
for i=1 to 5 do { straight } ] with .nw at last [].sw+(0,-0.2)
[ for dir=90 to 570 by 240 do {
curve(,dir,,tiecount=5;tie=outlined "gray" thick 2.5)
curve(, ,,tiecount=5;tie=outlined "gray" thick 2.5) }
] with .nw at 1st [].ne+(0.2,0)
PE