[metapost] Re: d\'ej\`a vu or turningnumber, area et caetera

Daniel H. Luecking luecking at uark.edu
Fri Feb 4 20:28:08 CET 2005

On Fri, 4 Feb 2005, Boguslaw Jackowski wrote:

> The problem of such paths can be easily solved. Let a, b, c, d denote the
> nodes of the B\'ezier segment a .. controls b and c .. d.
> A more general definition of `postdir' (and, for completeness, `predir'),
> given below, is based on the following observation, being the consequence of
> the de l'H\^ospital's rule: normally the vector a-->b determines the ``post''
> direction at node a; if b coincides with a, then the vector a-->c determines
> the direction; if c also coincides coincides with a, then the last resort is
> vector c-->d; if d also coincides with a, the B\'ezier segment is
> degenerated, and can be removed.

Mfpic's grafbase.mf (version 0.7) has postdirection and predirection.
It is used to determine the orientation of arrowheads at the end of
paths. Version 0.8 (coming Real Soon Now) uses a different approach, but
now uses these to create parallel paths.  The code follows.

% Note: "post[n](f)" = "postcontrol n of f", etc. Also, the time is
% not expected to be integral, and if a trivial segment (all
% four controls coinciding) occurs, the next segment is examined.

vardef predirection@# (expr p) =
  - postdirection[length p - @#] (reverse p)

vardef postdirection@# (expr p) =
  save _n; _n := length (p);
  save v; pair v;
  v:= __dir (subpath (@#, @# + _n) of p);
  if v = origin : % use predirection as a fallback
    v := - __dir (subpath (@#, @# - _n) of p);

vardef __dir (expr p) =
  save v, w; pair v, w; w := pnt0 (p);
  v := origin;
  for n = 1 upto length (p) :
    v := post[n-1] (p) - w; exitif v <> origin;
    v := pre [ n ] (p) - w; exitif v <> origin;
    v := pnt [ n ] (p) - w; exitif v <> origin;
  v if v<>(0,0): /abs(v) fi

vardef trivial primary p = __dir (p) = origin enddef;

> Now, `turn_ang' works quite efficiently (speed-up is some 30% in
> comparison with Werner's `is_clockwise') and yields ``reasonable''
> results for ``reasonable'' paths. It fails for paths with cusps,
> loops, and with segments turning by the angle >=180. Note that
> cusps and large turning angles are indifferent for the `Area' function.
> Ps. Note that the `direction' operator, defined in MP/MF as follows:
>        vardef direction expr t of p =
>         postcontrol t of p - precontrol t of p enddef;
>      can be improved using the functions `predir' and `postdir'
>      defined above:
>        vardef gendir expr t of p =
>         if round(t)=t:
>          predir t of p + postdir t of p
>         else:
>          gendir 1 of
>            ((subpath (floor t, t) of p) & (subpath (t, ceiling t) of p))
>         fi
>        enddef;

I personally think that at an integer t, a user should specify either
postdir or predir. There is little use in obtaining some intermediate
angle when they differ.


Dan Luecking
Dept. of Mathematical Sciences
University of Arkansas
Fayetteville, AR 72101

More information about the metapost mailing list