Initialization

> # First we must initialize...
restart;
with(VectorCalculus):
with(plots): #
# osculatingCircles := proc(curve_eq,r,t_begin,t_end,numPts,nFrames,nLine,x_min,x_max,y_min,y_max)
#
osculatingCircles := proc(curve_eq,r,t_begin,t_end)
   local T,N,kappa,kappa_t0,cir_radius,cir_center,t_0,cc_x,cc_y,osc_circle,
         pt_x0,pt_y0,norm_line,graphX_min,graphY_min,graphX_max,graphY_max,
         graphX_length,graphY_length,t,opts,numPts,nFrames,nLine,
         x_min,x_max,y_min,y_max;

   opts:= [args[5..-1]];

   # The normal line is shown by default.
   if nops(opts)<3 then
       nLine := true;
   else
       nLine := opts[3];
   end if;

   # The default number of points (used by implicitplot) is 1000.

   if nops(opts)<1 then
       numPts := 1000;
   else
       numPts := opts[1];
   end if;

   # The default number of frames shown is 50.
   if nops(opts)<2 then
       nFrames := 50;
   else
       nFrames := opts[2];
   end if;
   
   # Here is the unit tangent vector
   T := simplify(diff(r(t),t)/Norm(diff(r(t),t))) assuming t::real;

   # Here is the unit normal vector
   N := simplify(diff(T,t)/Norm(diff(T,t))) assuming t::real;

   # We don't need the binormal.

   # Here is the curvature
   kappa := simplify(Curvature(r(t),t)) assuming t::real;

   # We can now find the equation of the osculating circle at r(t_0)

   # The osculating circle has radius 1/kappa

   # kappa_t0 is the curvature at t=t_0.
   # If the curvature is 0, then there is no osculating circle (it would
   # need to have an infinite radius). At such a point we should use a
   # tangent line. But instead, I'll use a circle with a really huge
   # radius (which looks the same when graphed).
   kappa_t0 := eval(kappa,t=t_0);
   cir_radius := piecewise(kappa_t0=0,999999999,1/kappa_t0);

   # We find its center by starting at r(t_0) on our curve and then
   # traveling (in the unit normal N(t_0) direction) 1/kappa
   # (the radius of the circle) units.
   cir_center := r(t_0) + cir_radius*eval(N,t=t_0);

   # Finally, we dot circle_center with e_x and e_y in order to
   # rip-off the x and y coordinates of the center.
   cc_x := cir_center . <1,0,0>;
   cc_y := cir_center . <0,1,0>;

   # Here is the equation of the osculating circle at r(t_0)
   osc_circle := (x-cc_x)^2 + (y-cc_y)^2 = cir_radius^2;

   # Here is a line from the curve (at r(t_0)) to the center of the circle.
   pt_x0 := r(t_0) . <1,0,0>;
   pt_y0 := r(t_0) . <0,1,0>;

   norm_line := simplify((pt_x0 - cc_x)*(y - pt_y0) = (pt_y0 - cc_y)*(x - pt_x0));



   # Now let's plot some of these circles, normal lines, and the curve itself

   # To make sure that all of the circles fit in the plot window, we sample
   # some of the circles' extreme x,y coordinates (taking max's/min's). But
   # we also cap the length in case of crazy huge circles (like what happens
   # if we approach zero curvature) -- this is what the outer max's/min's and
   # graph??? variables are all about.
   graphX_min := min(seq(r(t_0).<1,0,0>,t_0=t_begin..t_end,(t_end-t_begin)/10)):
   graphY_min := min(seq(r(t_0).<0,1,0>,t_0=t_begin..t_end,(t_end-t_begin)/10)):
   graphX_max := max(seq(r(t_0).<1,0,0>,t_0=t_begin..t_end,(t_end-t_begin)/10)):
   graphY_max := max(seq(r(t_0).<0,1,0>,t_0=t_begin..t_end,(t_end-t_begin)/10)):
   graphX_length := graphX_max-graphX_min:
   graphY_length := graphY_max-graphY_min:


   if nops(opts)<7 then
      x_max := graphX_max+graphX_length*10:  
      x_min := graphX_min-graphX_length*10:
      y_max := graphY_max+graphY_length*10:
      y_min := graphY_min-graphY_length*10:
   else
      x_min := opts[4];
      x_max := opts[5];
      y_min := opts[6];
      y_max := opts[7];
   end if;

   # to view this animation, first click on the plot, then some buttons will appear
   # where the "[Text][Math][C Maple Input]..." toolbar used to be (above)
   #
   # for smoother animations, set frames to be something like 100
   # ***This calculation may take a minute or two***

   if nLine=true then
      animate(implicitplot, [[osc_circle, curve_eq, norm_line],
           x=x_min..x_max, y=y_min..y_max, numpoints=numPts], t_0=t_begin..t_end,
           frames=nFrames, scaling=constrained);
   else
      animate(implicitplot, [[osc_circle, curve_eq],
           x=x_min..x_max, y=y_min..y_max, numpoints=numPts], t_0=t_begin..t_end,
           frames=nFrames, scaling=constrained);
   end if      
end proc: