Search code examples
geometryoctave

How to determine if a point belongs to a parametric curve in Octave?


I have this parametric equation of a 'flower':

x(t) = (r+cos(nlep*t))cos(t),

y(t) = (r+cos(nlep*t))sin(t)

where nlep is the numper of petals, r - radius. I want to create a trajectory that bounces (reflects maybe) inside this curve starting at (0,0). The problem I came across is that I can't seem to be able to determine whether a point belongs to a curve. I need that to calculate when to change direction. It seems not possible to exclude t parameter. So I tried to sovle a system of nonlinear equations. However, I am not sure how to set the initial value of t whenever I solve the system. Here is my code:

t = linspace(-10, 10, 100);
x = (r + cos(nlep*t)).*cos(t);
y = (r + cos(nlep*t)).*sin(t);
plot(x, y, 'g')
hold on

So for example I am going alone a horizontal line and want to determine points which belong to a curve:

p = linspace(min(x), max(x), 100);
for j=1:length(p)
  f = @(t) ([((r + cos(nlep*t)).*cos(t))-p(j); ((r + cos(nlep*t)).*sin(t))-3]);
  [t0, fval, info] = fsolve(f, t(j));
  if info==1 # info is never 1
    plot(p(j), 3, 'r')  
  endif
endfor

But nothing apart from the curve itself is plotted. What should be the way to do it? Could somebody please give a hint? Thanks in advance.


Solution

  • Your system doesn't typically have a solution - it's a system of two equations with just one unknown, t. fsolve can only minimize the norm of the two function results, but it can't make both zero for the same t.

    If I understood correctly, you want to find the intersections of the curve with a line, let's say y = a * x + b, with known values of a and b. Then, you have to solve one equation:

    f = @(t) a * (r + cos(nlep*t)).*cos(t) + b - (r + cos(nlep*t)).*sin(t);
    

    which is a * x + b - y with x and y replaced by the curve parametric form. After you found the solution, t0, the coordinates are found by applying the parametric formulae, x0 = (r + cos(nlep*t0)) * cos(t0) and y0 = (r + cos(nlep*t0)) * sin(t0) - obviously, the solution point is part of the curve.

    Here's the curve, line and solution plot in a particular case:

    r = 1; nlep = 5;
    
    t = linspace(-pi, pi, 100);
    x = (r + cos(nlep*t)).*cos(t);
    y = (r + cos(nlep*t)).*sin(t);
    plot(x, y, 'g')
    hold on
    
    a = 1; b = 0.5; # y = x + 0.5
    
    % plot the line
    p = linspace(min(x), max(x), 100);
    yp = a * p + b;
    plot(p, yp, '-b')
    
    % find and plot an intersection point
    f = @(t) a * (r + cos(nlep*t)).*cos(t) + b - (r + cos(nlep*t)).*sin(t);
    [t0, fval, info] = fsolve(f, t(j));
    
    if info==1
      x0 = (r + cos(nlep*t0))*cos(t0);
      y0 = (r + cos(nlep*t0))*sin(t0);
      disp([x0, y0]);
      % plot the solution point
      plot(x0, y0, '*r', 'MarkerSize', 10)
    endif
    
    hold off
    

    The problem here is that this procedure can only find one solution. To find many/all solutions, one has to try with different initial values for t. Here's a possible version for the final part of the previous piece of code:

    % find and plot all intersection points
    x0 = [];
    y0 = [];
    
    f = @(t) a * (r + cos(nlep*t)).*cos(t) + b - (r + cos(nlep*t)).*sin(t);
    
    for tinitial = linspace(-pi, pi, 20)
      [t0, fval, info] = fsolve(f, tinitial);
      if info==1
        x0new = (r + cos(nlep*t0))*cos(t0);
        y0new = (r + cos(nlep*t0))*sin(t0);
        
        % check if the new solution wasn't already found
        exists = false;
        for i = 1:length(x0)
          if(abs(x0(i)-x0new) + abs(y0(i)-y0new) < 1e-5)
            exists = true;
            break;
          endif
        endfor
    
        if not(exists) % inefficient, but it happens only a few times.
          x0 = [x0, x0new];
          y0 = [y0, y0new];
        endif
      endif
    endfor
    
    disp(sprintf('%d solutions found', length(x0)))
    
    % plot the solution points
    plot(x0, y0, '*r', 'MarkerSize', 10)
    
    hold off