This arrowhead does not inherit the parameterization from MetaPostArrow, although frontAngle corresponds to ahAngle. Instead of ahLength, there is width, and there is the additional parameter rearAngle.
If width is a §Float, it is implicitly multiplied by ..Shapes..Traits..@width, but truncated at 3 bp from below. Widths smaller than 3 bp can still be obtained by specifying the width directly as a §Length. By defining an arrowhead as a dynamic variable, it is even possible to make the width your own function of ..Shapes..Traits..@width, like so:
dynamic @myHead identity dynamic [ShapesArrow width:@width*(1.5+4.5bp/(1bp+@width)) ...]
An example is included to illustrate how the shape of the arrowhead is determined.
Geometry of the ShapesArrow |
---|
|
The shape of the ShapesArrow arrowhead on a bent path is defined by generalization of how the arrowhead is defined for straight paths. Looking at the arrowhead on the straight path, the shape of each triangular hook is determined by the length w and the angles α and β. From the triangle, the distances r, h, and l are determined. From the red point at the rear of the arrowhead, the tangent direction at that point, the angle β, and the distance r, the outer red points are determined. The outer blue paths are then obtained by scaling and rotation of the central blue path of length h, so that they join the front red point with the corresponding outer red point. The outer red points are connected with straight lines to the rear red point.
Note that the construction of the arrowhead does not (unless the path is straight) result in an angle of exactly frontAngle at the front, and that the two tangents at the front may not be symmetric with respect to the tangent direction of the underlying path. However, as the illustration shows, the deviations may hardly be noticeable.
|
| Source:
show/hide
—
visit
|
##needs ..Applications..Blockdraw
##needs ..Shapes..Geometry / pathmapping
##preamble \usepackage{amsmath}
##lookin ..Shapes
##lookin ..Shapes..Geometry
##lookin ..Applications..Blockdraw
lengthMarks: \ n p r:void a:75° →
{
the_r: [if [typeof r]=Data..Type..§Void Traits..@width*10 r]
d: 0.5 * the_r
rot: [rotate a]
l_p: (|p|)
(>
picture:
[[Data..range '0 n-'1].foldl
\ pile e →
pile &
{
sl: [p 0.5*l_p + ( e*1 - 0.5*(n-'1) ) * d]
[shift sl.p]*rot [] [Graphics..stroke the_r*sl.T--~the_r*sl.T]
}
Graphics..null]
cut:0m
<)
}
IO..•page << [shift (~4cm,~1cm)][][Layout..center [Graphics..TeX `
\begin{minipage}{6cm}
\begin{align*}
2\, \alpha &= \text{\texttt{frontAngle}}
\\
2\, \beta &= \text{\texttt{rearAngle}}
\\
2\, w &=
\begin{cases}
\text{\texttt{width}}, & \text{if \texttt{width} is a Data..Type..§Length}
\\
\max \left\{\, 3\,\mathrm{bp},\, \text{\texttt{width}}\, \text{\texttt{Traits..@width}} \,\right\}, & \text{if \texttt{width} is a Data..Type..§Float}
\end{cases}
\end{align*}
\end{minipage}
´] (~1,~1)]
Traits..@width:1cm
|
{
pth: { c: [Geometry..circle 5cm] [c 2.3]--[c 3.3] }
/** First we set up variables that mirror the formal parameters of ShapesArrow.
**/
p: [Geometry..reverse pth]
width:3
frontAngle:40°
rearAngle:150°
/** Show the arrowhead.
**/
IO..•page << Traits..@stroking:[Traits..gray 0.7] | [Graphics..stroke pth head:[Graphics..ShapesArrow width:width frontAngle:frontAngle rearAngle:rearAngle ...]]
/** Then we paste the implementation of ShapesArrow...
**/
z: p.begin.p
lMax: 0.99*[Numeric..Math..abs p]
w: 0.5*[if [typeof width]=Data..Type..§Float Traits..@width*width width]
el: [Numeric..Math..min w/[Numeric..Math..sin 0.5*frontAngle] lMax]
l: [Numeric..Math..min w * ( [Numeric..Math..cot 0.5*frontAngle] - [Numeric..Math..cot 0.5*rearAngle] ) lMax]
e: [p 0]--[p el] >> [shift ~z]
sl: [p l]
pr: sl.p
dr: e.end.p
dra: [angle dr]
drl: (|dr|)
r: w / [Numeric..Math..sin 0.5*rearAngle]
d1: sl.p + [[rotate 0.5*rearAngle] (r*sl.T)] - z
d2: sl.p + [[rotate ~0.5*rearAngle] (r*sl.T)] - z
/** The following paths are not bound to variables in the implementation, but we need them here.
**/
e1: [[shift z]*[rotate [angle d1]-dra]*[scale (|d1|)/drl] e]
e2: [[shift z]*[rotate [angle d2]-dra]*[scale (|d2|)/drl] e]
/** ... so that we can annotate the result!
**/
IO..•page << Traits..@width:3bp & Traits..@stroking:[Traits..gray 0.8] | [Graphics..stroke pth]
Traits..@width:1.5bp & Traits..@stroking:Traits..RGB..BLUE
|
{
IO..•page << [Graphics..stroke [shift z][]e]
<< [Graphics..stroke e1]
<< [Graphics..stroke e2]
}
Traits..@width:5bp & Traits..@stroking:Traits..RGB..RED
|
{
IO..•page << [Graphics..spot pr] << [Graphics..spot z] << [Graphics..spot e1.end.p] << [Graphics..spot e2.end.p]
}
hStyle: Traits..@width:0.5bp & Traits..@stroking:[Traits..gray 0.2]
angleHead: [Graphics..ShapesArrow width:2bp ...]
hStyle
|
{
r0: 1cm
r1: 2.5cm
r2: 3.5cm
IO..•page << [Graphics..stroke [shift z][]( e1.begin.T*r0--e1.begin.T*~r1 )]
IO..•page << [Graphics..stroke [shift z][]( e2.begin.T*r0--e2.begin.T*~r1 )]
{
rAngle: 0.8*r1
arc: [shift z] [] [Geometry..ccw_arc (0m,0m) [rotate ~(5mm/rAngle)][]e2.begin.T*~r1 e2.begin.T*~r1 rAngle]
IO..•page << [Graphics..stroke [shift z] [] [Geometry..ccw_arc (0m,0m) e2.begin.T*~r1 e1.begin.T*~r1 rAngle]]
<< [Graphics..stroke [shift z] [] [Geometry..cw_arc (0m,0m) [rotate (5mm/rAngle)][]e1.begin.T*~r1 e1.begin.T*~r1 rAngle]
head:angleHead]
<< [Graphics..stroke arc head:angleHead]
<< [putlabelRight [Graphics..TeX `$\approx 2\, \alpha$´] arc.begin.p ~1]
}
{
arc1: [shift z] [] [Geometry..cw_arc (0m,0m) e1.begin.T*~r1 p.begin.T*~r1 0.5*(r1+r2)]
arc2: [shift z] [] [Geometry..ccw_arc (0m,0m) e2.begin.T*~r1 p.begin.T*~r1 0.5*(r1+r2)]
IO..•page << [Graphics..stroke z--(+~r2*p.begin.T)]
<< [Graphics..stroke [[shift z]*[rotate 0.5*frontAngle] ~(r1+1bp)*p.begin.T--(+(~(r2-r1)*p.begin.T))]]
<< [Graphics..stroke [[shift z]*[rotate ~0.5*frontAngle] ~(r1+1bp)*p.begin.T--(+(~(r2-r1)*p.begin.T))]]
<< [Graphics..stroke arc1 head:angleHead tail:angleHead]
<< [Graphics..stroke arc2 head:angleHead tail:angleHead]
<< [putlabelRight [Graphics..TeX `$\alpha$´] [Layout..mspoint arc1 0.5] ~1]
<< [putlabelRight [Graphics..TeX `$\alpha$´] [Layout..mspoint arc2 0.5] ~1]
}
{
p: e1.end.p--pr
IO..•page << [Graphics..stroke p]
<< [putlabelRight [Graphics..TeX `$r$´] [Layout..mspoint p 0.5] 0]
}
{
p: pr--e2.end.p
IO..•page << [Graphics..stroke p]
<< [putlabelRight [Graphics..TeX `$r$´] [Layout..mspoint p 0.5] 0]
}
{
pw: pr + [Numeric..Math..cos 0.5*rearAngle]*r*sl.T
p1: pw--e1.end.p
p2: pw--e2.end.p
IO..•page << [Graphics..stroke p1 head:angleHead tail:angleHead]
<< [putlabelLeft [Graphics..TeX `$w$´] [Layout..mspoint p1 0.5] 1]
<< [Graphics..stroke p2 head:angleHead tail:angleHead]
<< [putlabelLeft [Graphics..TeX `$w$´] [Layout..mspoint p2 0.5] ~1]
}
{
hLine: pr--(+(1.2*r*sl.T))
arc1: [Geometry..ccw_arc pr hLine.end.p e1.end.p 0.9*r]
arc2: [Geometry..cw_arc pr hLine.end.p e2.end.p 0.9*r]
IO..•page << [Graphics..stroke hLine]
<< [Graphics..stroke arc1 head:angleHead tail:angleHead]
<< [putlabelLeft [Graphics..TeX `$\beta$´] [Layout..mspoint arc1 0.5] 1]
<< [Graphics..stroke arc2 head:angleHead tail:angleHead]
<< [putlabelLeft [Graphics..TeX `$\beta$´] [Layout..mspoint arc2 0.5] ~1]
}
{
offset: 5bp
arc0: p.begin--[p l]
arc: [Geometry..sidepath2 [Geometry..upsample_bends 20° arc0] offset]
IO..•page << [Graphics..stroke arc head:angleHead tail:angleHead]
<< [Graphics..stroke arc0.begin.p--(+arc0.begin.N*1.5*offset)]
<< [Graphics..stroke arc0.end.p--(+arc0.end.rN*~2*offset)]
<< [putlabelBelow [Graphics..TeX `$l$´] [Layout..mspoint arc 0.8] 0]
}
{
offset: ~5bp
arc0: [shift z][]e
arc: [Geometry..sidepath2 [Geometry..upsample_bends 20° arc0] offset]
IO..•page << [Graphics..stroke arc head:angleHead tail:angleHead]
<< [Graphics..stroke arc0.begin.p--(+arc0.begin.N*1.5*offset)]
<< [Graphics..stroke arc0.end.p--(+arc0.end.rN*~2*offset)]
<< [putlabelAbove [Graphics..TeX `$h$´] [Layout..mspoint arc 0.7] 0]
}
}
}
Traits..@width:1cm
|
{
pth: (~5cm,~10cm)--(3cm,(+0cm))
/** First we set up variables that mirror the formal parameters of ShapesArrow.
**/
p: [Geometry..reverse pth]
width:3
frontAngle:40°
rearAngle:150°
/** Show the arrowhead.
**/
IO..•page << Traits..@stroking:[Traits..gray 0.7] | [Graphics..stroke pth head:[Graphics..ShapesArrow width:width frontAngle:frontAngle rearAngle:rearAngle ...]]
/** Then we paste the implementation of ShapesArrow...
**/
z: p.begin.p
lMax: 0.99*[Numeric..Math..abs p]
w: 0.5*[if [typeof width]=Data..Type..§Float Traits..@width*width width]
el: [Numeric..Math..min w/[Numeric..Math..sin 0.5*frontAngle] lMax]
l: [Numeric..Math..min w * ( [Numeric..Math..cot 0.5*frontAngle] - [Numeric..Math..cot 0.5*rearAngle] ) lMax]
e: [p 0]--[p el] >> [shift ~z]
sl: [p l]
pr: sl.p
dr: e.end.p
dra: [angle dr]
drl: (|dr|)
r: w / [Numeric..Math..sin 0.5*rearAngle]
d1: sl.p + [[rotate 0.5*rearAngle] (r*sl.T)] - z
d2: sl.p + [[rotate ~0.5*rearAngle] (r*sl.T)] - z
/** The following paths are not bound to variables in the implementation, but we need them here.
**/
e1: [[shift z]*[rotate [angle d1]-dra]*[scale (|d1|)/drl] e]
e2: [[shift z]*[rotate [angle d2]-dra]*[scale (|d2|)/drl] e]
/** ... so that we can annotate the result!
**/
IO..•page << Traits..@width:3bp & Traits..@stroking:[Traits..gray 0.8] | [Graphics..stroke pth]
Traits..@width:1.5bp & Traits..@stroking:Traits..RGB..BLUE
|
{
IO..•page << [Graphics..stroke [shift z][]e]
<< [Graphics..stroke e1]
<< [Graphics..stroke e2]
}
Traits..@width:5bp & Traits..@stroking:Traits..RGB..RED
|
{
IO..•page << [Graphics..spot pr] << [Graphics..spot z] << [Graphics..spot e1.end.p] << [Graphics..spot e2.end.p]
}
hStyle: Traits..@width:0.5bp & Traits..@stroking:[Traits..gray 0.2]
angleHead: [Graphics..ShapesArrow width:2bp ...]
hStyle
|
{
{
rLbl: 2cm
arc1: [Geometry..ccw_arc z pr e1.end.p rLbl]
arc2: [Geometry..cw_arc z pr e2.end.p rLbl]
IO..•page << [Graphics..stroke arc1 head:angleHead tail:angleHead]
<< [putlabelLeft [Graphics..TeX `$\alpha$´] [Layout..mspoint arc1 0.5] 0]
<< [Graphics..stroke arc2 head:angleHead tail:angleHead]
<< [putlabelLeft [Graphics..TeX `$\alpha$´] [Layout..mspoint arc2 0.5] ~0.5]
}
{
p: e1.end.p--pr
IO..•page << [Graphics..stroke p]
<< [putlabelRight [Graphics..TeX `$r$´] [Layout..mspoint p 0.5] 0]
}
{
p: pr--e2.end.p
IO..•page << [Graphics..stroke p]
<< [putlabelRight [Graphics..TeX `$r$´] [Layout..mspoint p 0.5] 0]
}
{
pw: pr + [Numeric..Math..cos 0.5*rearAngle]*r*sl.T
p1: pw--e1.end.p
p2: pw--e2.end.p
IO..•page << [Graphics..stroke p1 head:angleHead tail:angleHead]
<< [putlabelLeft [Graphics..TeX `$w$´] [Layout..mspoint p1 0.5] 1]
<< [Graphics..stroke p2 head:angleHead tail:angleHead]
<< [putlabelLeft [Graphics..TeX `$w$´] [Layout..mspoint p2 0.5] ~1]
}
{
hLine: pr--(+(1.2*r*sl.T))
arc1: [Geometry..ccw_arc pr hLine.end.p e1.end.p 0.9*r]
arc2: [Geometry..cw_arc pr hLine.end.p e2.end.p 0.9*r]
IO..•page << [Graphics..stroke hLine]
<< [Graphics..stroke arc1 head:angleHead tail:angleHead]
<< [putlabelLeft [Graphics..TeX `$\beta$´] [Layout..mspoint arc1 0.5] 1]
<< [Graphics..stroke arc2 head:angleHead tail:angleHead]
<< [putlabelLeft [Graphics..TeX `$\beta$´] [Layout..mspoint arc2 0.5] ~1]
}
{
offset: 5bp
arc0: p.begin--[p l]
arc: [Geometry..sidepath [Geometry..upsample_bends 20° arc0] offset]
IO..•page << [Graphics..stroke arc head:angleHead tail:angleHead]
<< [Graphics..stroke arc0.begin.p--(+arc0.begin.N*1.5*offset)]
<< [Graphics..stroke arc0.end.p--(+arc0.end.rN*~2*offset)]
<< [putlabelBelow [Graphics..TeX `$l$´] [Layout..mspoint arc 0.8] 0]
}
{
offset: ~5bp
arc0: [shift z][]e
arc: [Geometry..sidepath [Geometry..upsample_bends 20° arc0] offset]
IO..•page << [Graphics..stroke arc head:angleHead tail:angleHead]
<< [Graphics..stroke arc0.begin.p--(+arc0.begin.N*1.5*offset)]
<< [Graphics..stroke arc0.end.p--(+arc0.end.rN*~2*offset)]
<< [putlabelAbove [Graphics..TeX `$h$´] [Layout..mspoint arc 0.7] 0]
<< [putlabelBelow [Graphics..TeX `$h$´] [Layout..mspoint e1 0.7] 0]
<< [putlabelAbove [Graphics..TeX `$h$´] [Layout..mspoint e2 0.7] 0]
}
}
}
|
|