5

Assuming that I have the path P given, and let the T be a point outside the path P. Is there an easy way to find the point X on the path P such that the tangent on point X going through the point T?

Example in Metapost:

outputformat := "svg";
outputtemplate := "%j-%c.svg";
beginfig(1)
pair T,X; path P;
T:=(800,900); P:=(0,0)..(300,100)..(200,600);
draw P withpen pencircle scaled 10;
draw T withpen pencircle scaled 20 withcolor red;
endfig; end

Basically, what I need is: X = directionpoint (T-X) of P (this is, of course, an error).

The only solution I can think of is to check an every point on the path until I found it, something like:

numeric v; v:=0;
forever: X:=point v of P;
exitif abs(angle(T-X) - angle(direction v of P)) < 0.001; % for example
v:=v+epsilon; endfor;

Of course, this specific code will not work in the every case. Plus, it's very slow.

Is there a better solution? Of course, in a general case it's possible that there is no the solution, or more than just one solution.

2
  • we can probably do it with the solve macro
    – Thruston
    Nov 5 '21 at 19:02
  • The arc is a general path rather than the arc of a circle?
    – Thruston
    Nov 5 '21 at 19:05
5

Try this:

outputformat := "svg";
outputtemplate := "%j-%c.svg";
beginfig(1);
pair T,X; path P;
T:=(800,900); P:=(0,0)..(300,100)..(200,600);
draw P withpen pencircle scaled 10;
draw T withpen pencircle scaled 20 withcolor red;

vardef f(expr t) = angle direction t of P - angle (T - point t of P) < eps enddef;
X = point solve f (0, 2) of P;
draw X -- T withpen pencircle scaled 5 withcolor red;

endfig; end

which gets me this (although I was using eps as the output format and converting it to png to get this actual pic)

enter image description here

The solve macro is explained in The Metafont Book pp.176-177. Paraphrasing, the macro uses a binary search to find a numeric (brute force) solution to a non-linear equation. You have to define a macro with a single parameter that returns either true or false. You then pass the name of your macro to solve as a suffix, followed by a pair (a, b) such that f(a) is true and f(b) is false. The solve macro returns a value between a and b that is "at the cutting edge between truth and falsity".

You can find the macro in your local copy of plain.mp:

vardef solve@#(expr true_x,false_x)= 
 tx_:=true_x; fx_:=false_x;
 forever: x_:=.5[tx_,fx_]; exitif abs(tx_-fx_)<=tolerance;
 if @#(x_): tx_ else: fx_ fi :=x_; endfor
 x_ enddef; % now x_ is near where @# changes from true to false
newinternal tolerance, tx_,fx_,x_; tolerance:=.01;

Notice how the passed macro is called with @#(x_)...

1
  • Great solution! Of course, it's not an universal solution, but for the my purposes it's absolutely perfect!
    – Урош
    Nov 7 '21 at 14:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.