Search code examples
randomprocessingcalculus

Finding a Tangent Line at a Point on a Randomized Slope


I have a piece of processing code that I was given, which appears to be setting up a randomized Fourier series. Unfortunately, despite my efforts to improve my mathematical skills, I have no idea what it is doing and the articles I have found are not much help.

I'm trying to extend this code so that I can draw a line tangent to a point on the slope created by the code bellow. The closest I can find to answering this is in the mathematics forum. Unfortunately, I don't really understand what is being discussed or if it really is relevant to my situation.

Any assistance on how I would go about calculating a tangent line at a particular point on this curve would be much appreciated.

UPDATE As of 06/17/13

I've been trying to play around with this, but without much success. This is the best I can do, and I doubt that I'm applying the derivative correctly to find the tangent (or even if I have found the derivative at the point correctly). Also, I'm beginning to worry that I'm not drawing the line correctly even if I have everything else correct. If anyone can provide input on this I'd appreciate it.

final int w = 800;
final int h = 480;
double[] skyline;
PImage img;
int numOfDeriv = 800;
int derivModBy = 1; //Determines how many points will be checked
int time;
int timeDelay = 1000;
int iter;
double[] derivatives;

void setup() {
  noStroke();
  size(w, h);
  fill(0,128,255);
  rect(0,0,w,h);
  int t[] = terrain(w,h);
  fill(77,0,0);
  for(int i=0; i < w; i++){
    rect(i, h, 1, -1*t[i]);
  }
  time = millis();
  timeDelay = 100;
  iter =0;
  img = get();
}

void draw() {
  int dnum = 0; //Current position of derivatives
  if(iter == numOfDeriv) iter = 0;
  if (millis() > time + timeDelay){
        image(img, 0, 0, width, height);
        strokeWeight(4);
        stroke(255,0,0);        
        point((float)iter*derivModBy, height-(float)skyline[iter*derivModBy]);
        strokeWeight(1);
        stroke(255,255,0);
        print("At x = ");
        print(iter);
        print(", y = ");
        print(skyline[iter]);
        print(", derivative = ");
        print((float)derivatives[iter]);
        print('\n');
        lineAngle(iter, (int)(height-skyline[iter]), (float)derivatives[iter], 100);
        lineAngle(iter, (int)(height-skyline[iter]), (float)derivatives[iter], -100);
        stroke(126);
        time = millis();
        iter += 1;
    }
}

void lineAngle(int x, int y, float angle, float length)
{
  line(x, y, x+cos(angle)*length, y-sin(angle)*length);
}

int[] terrain(int w, int h){

    width = w;
    height = h;

    //min and max bracket the freq's of the sin/cos series
    //The higher the max the hillier the environment
    int min = 1, max = 6;

    //allocating horizon for screen width
    int[] horizon = new int[width];
    skyline =  new double[width];
    derivatives = new double[numOfDeriv];

    //ratio of amplitude of screen height to landscape variation
    double r = (int) 2.0/5.0;

    //number of terms to be used in sine/cosine series
    int n = 4;

    int[] f = new int[n*2];

    //calculating omegas for sine series
    for(int i = 0; i < n*2 ; i ++){
      f[i] = (int) random(max - min + 1) + min;
    }

    //amp is the amplitude of the series
    int amp =  (int) (r*height);
    int dnum = 0; //Current number of derivatives    
    for(int i = 0 ; i < width; i ++){
      skyline[i] = 0;
      double derivative = 0.0;
      for(int j = 0; j < n; j++){
         if(i % derivModBy == 0){
            derivative += ( cos( (f[j]*PI*i/height) * f[j]*PI/height) - 
                        sin(f[j+n]*PI*i/height) * f[j+n]*PI/height);
         }

        skyline[i] += ( sin( (f[j]*PI*i/height) ) +  cos(f[j+n]*PI*i/height) );
        }
      skyline[i] *= amp/(n*2);
      skyline[i] += (height/2);
      skyline[i] = (int)skyline[i];
      horizon[i] = (int)skyline[i];
      derivative *= amp/(n*2);
      if(i % derivModBy == 0){
        derivatives[dnum++] = derivative;
        derivative = 0;
      }
    }

    return horizon;
}

void reset() {
  time = millis();
}

Solution

  • I received an answer to this problem via "quarks" on processing.org form. Essentially the problem is that I was taking the derivative of each term of the series instead of taking the derivative of the sum of the entire series. Also, I wasn't applying my result correctly anyway.

    Here is the code that quarks provided that definitively solves this problem.

    final int w = 800;
    final int h = 480;
    float[] skyline;
    PImage img;
    int numOfDeriv = 800;
    int derivModBy = 1; //Determines how many points will be checked
    int time;
    int timeDelay = 1000;
    int iter;
    float[] tangents;
    
    public void setup() {
      noStroke();
      size(w, h);
      fill(0, 128, 255);
      rect(0, 0, w, h);
      terrain(w, h);
      fill(77, 0, 0);
      for (int i=0; i < w; i++) {
        rect(i, h, 1, -1*(int)skyline[i]);
      }
      time = millis();
      timeDelay = 100;
      iter =0;
      img = get();
    }
    
    public void draw() {
      if (iter == numOfDeriv) iter = 0;
      if (millis() > time + timeDelay) {
        image(img, 0, 0, width, height);
        strokeWeight(4);
        stroke(255, 0, 0);        
        point((float)iter*derivModBy, height-(float)skyline[iter*derivModBy]);
        strokeWeight(1);
        stroke(255, 255, 0);
        print("At x = ");
        print(iter);
        print(", y = ");
        print(skyline[iter]);
        print(", derivative = ");
        print((float)tangents[iter]);
        print('\n');
        lineAngle(iter, (int)(height-skyline[iter]), (float)tangents[iter], 100);
        lineAngle(iter, (int)(height-skyline[iter]), (float)tangents[iter], -100);
        stroke(126);
        time = millis();
        iter += 1;
      }
    }
    
    public void lineAngle(int x, int y, float angle, float length) {
      line(x, y, x+cos(angle)*length, y-sin(angle)*length);
    }
    
    public void terrain(int w, int h) {      
      //min and max bracket the freq's of the sin/cos series
      //The higher the max the hillier the environment
      int min = 1, max = 6;
      skyline =  new float[w];
      tangents = new float[w];
      //ratio of amplitude of screen height to landscape variation
      double r = (int) 2.0/5.0;
      //number of terms to be used in sine/cosine series
      int n = 4;
      int[] f = new int[n*2];
      //calculating omegas for sine series
      for (int i = 0; i < n*2 ; i ++) {
        f[i] = (int) random(max - min + 1) + min;
      }
      //amp is the amplitude of the series
      int amp =  (int) (r*h);
      for (int i = 0 ; i < w; i ++) {
        skyline[i] = 0;
        for (int j = 0; j < n; j++) {
          skyline[i] += ( sin( (f[j]*PI*i/h) ) +  cos(f[j+n]*PI*i/h) );
        }
        skyline[i] *= amp/(n*2);
        skyline[i] += (h/2);
      }
      for (int i = 1 ; i < w - 1; i ++) {
        tangents[i] = atan2(skyline[i+1] - skyline[i-1], 2);
      }
      tangents[0] = atan2(skyline[1] - skyline[0], 1);
      tangents[w-1] = atan2(skyline[w-2] - skyline[w-1], 1);
    }
    
    void reset() {
      time = millis();
    }