[NTG-context] MetaFun: How to draw bent paths?

Alan Braslau braslau.list at comcast.net
Wed Sep 19 18:25:09 CEST 2018


On Wed, 19 Sep 2018 11:18:30 +1200
Henri Menke <henrimenke at gmail.com> wrote:

> On 18/09/18 21:23, Henri Menke wrote:
> > On 9/18/18 7:57 PM, Hans Hagen wrote:  
> >> On 9/16/2018 10:28 AM, Henri Menke wrote:  
> >>> Dear list,
> >>>
> >>> I want to draw paths between points which are bent by a certain angle.
> >>> The code in the MWE below works well but I was thinking that the expert
> >>> here can surely improve it and suggest a nicer syntax.  
> >> looks like a challenge for Alan ... isn't it also a bit 3d (2.5d)?  
> > 
> > I wasn't thinking about a 3D application here, just a little bend on the
> > path to go around other elements in my drawing without having to think
> > about explicit control points (like the second example in my original
> > post).  In the meantime I have improved the defintion of the macro to
> > avoid double computation of the angle:
> > 
> >     vardef bend(expr a,b,phi) =
> >         save x ;
> >         x := angle(b-a) ;
> >         a{dir(x+phi)} .. {dir(x-phi)}b
> >     enddef ;
> > 
> > So currently the applied syntax is
> > 
> >     drawarrow bend(z1, z2, 30) ;
> > 
> > However, I would prefer something like
> > 
> >     drawarrow z1 bend(30) z2 ;
> > 
> > I'm not sure whether this is possible though.  Actually I'm reading the
> > MetaPost manual right know because my MP skills are rather poor.  
> 
> I think I got it now.  Not sure whether “bend” should be primary or
> something else.
> 
> \startMPdefinitions
>     primarydef a bend phi =
>         do_bend(a,phi)
>     enddef ;
> 
>     vardef do_bend(expr a, phi) expr b =
>         save x ;
>         x := angle(b-a) ;
>         a{dir(x+phi)} .. {dir(x-phi)}b
>     enddef ;
> \stopMPdefinitions
> 
> \starttext
> 
> \startMPpage
>     z1 = (-.5cm,1cm) ;
>     z2 = (1cm,3cm) ;
> 
>     for phi = 0 step 5 until 360:
>         draw z1 bend(phi) z2 withcolor (phi/360)[red,blue] ;
>     endfor ;
> \stopMPpage
> 
> % Possible use case:
> 
> \startMPpage[offset=1cm]
>     z1 = (-.5cm,1cm) ;
>     z2 = (1cm,3cm) ;
>     draw z1 -- z2 ;
>     dotlabel.lft("$-$", z1) ;
>     dotlabel.lft("$+$", z2) ;
> 
>     path p; p := z1 bend(-30) z2 ;
>     drawdblarrow p withcolor blue ;
>     label.lrt(textext("$\Delta$"),point .5 along p)  withcolor blue ;
> \stopMPpage
> 
> \stoptext


Henri,

1. I added a sanity test (angle(origin) is undefined);
2. it is probably more efficient to calculate the angle twice than to allocate storage;
3. primary b;

4. then I created the variant arc (as in a bow) taking a delta (the tangent of
   an angle).

Alan


\startMPdefinitions
    primarydef a bend phi =
        do_bend(a,phi)
    enddef ;

    vardef do_bend(expr a, phi) primary b =
        if abs(a-b)=0 :
            a
        else :
            (a{dir(angle(b-a)+phi)} .. {dir(angle(b-a)-phi)}b)
        fi
    enddef ;

    primarydef a arc delta =
        do_arc(a,delta)
    enddef ;

    vardef do_arc(expr a,delta) primary b =
        if abs(a-b)=0 :
            a
        else :
            (a .. unitvector direction .5 of (a--b) rotated 90
                 scaled delta * arclength (a--b)
                 shifted .5[a,b]
               .. b)
        fi
    enddef ;
\stopMPdefinitions

\starttext

\startMPpage
    z1 = (-.5cm,1cm) ;
    z2 = (1cm,3cm) ;

    for phi = 0 step 5 until 360:
        draw z1 bend phi z2 withcolor (phi/360)[red,blue] ;
    endfor ;
\stopMPpage

\startMPpage
    z1 = (-.5cm,1cm) ;
    z2 = (1cm,3cm) ;

    for delta = -1 step .1 until 1:
        draw z1 arc delta z2 withcolor ((delta+1)/2)[red,blue] ;
    endfor ;
\stopMPpage

% Possible use case:

\startMPpage[offset=1cm]
    z1 = (-.5cm,1cm) ;
    z2 = (1cm,3cm) ;
    draw z1 -- z2 ;
    dotlabel.lft("$-$", z1) ;
    dotlabel.lft("$+$", z2) ;

    path p; p := z1 bend(-30) z2 ;
    drawdblarrow p withcolor blue ;
    label.lrt(textext("$\Delta$"),point .5 along p)  withcolor blue ;
\stopMPpage

\stoptext


More information about the ntg-context mailing list