Tracing a line with PVector

edited October 2013 in Questions about Code

Hello all,

I'm trying to get a point to trace a line. I'm using PVectors to create the line and then using that information as a way to draw the point. The problem I'm finding at the moment is the point often traces the line well but other times it's a pixel off in one direction. I'm not sure where this is going wrong as they're getting the coordinates from the same variables. I would also appreciate knowing if this is the best way to build the lines (PVectors, Arraylists?).

My next task is getting the point to reset to the beginning once it's reached the end of the line. You'll notice the Processing currently errors out. Any pointers in the right direction for this would be most appreciated. Here's my current code:

TraceLine t1;

void setup() {
  size(800, 500);
  background(100);
  stroke(255);
  strokeWeight(1);
  smooth();

  t1=new TraceLine(50, 100);
  //t1.drawLines();
}

void draw() {
  background(100);
  t1.drawLines();
  t1.drawPoint();
}

class TraceLine {
  PVector p1;
  PVector p2;

  boolean direction;
  boolean horizontal;
  int steps=5;
  //int steps=int(random(5, 10));

  float [] horizontals;
  float [] diagonals;
  PVector[] TLine=new PVector[steps*2];

  PVector PointLocation;
  PVector velocity;
  PVector acceleration;
  int step=0;

  TraceLine(int p1x_, int p1y_) {
    horizontal=true;

    horizontals=new float[steps];
    diagonals=new float[steps];

    for (int i=0;i<steps;i++) {
      horizontals[i]=random(10, 60);
      diagonals[i]=random(5, 10);
    }

    p1=new PVector(p1x_, p1y_);
    p2=new PVector(p1.x, p1.y);
    PointLocation=new PVector(0, 0);
    TLine[0]=new PVector(p1.x, p1.y);

    velocity=new PVector(0, 0);
    setLine();
    println(TLine);
  }


  void setLine() {
    for (int i=1; i<=TLine.length-1;i++) {
      p1=p2;
      if (horizontal) {
        TLine[i]=new PVector(p2.x=p1.x+horizontals[i/2], p2.y=p1.y);
        horizontal=false;
      }
      else {
        //Choose up or down. true is up
        direction=boolean( int(random(0, 2)) );
        //If we're going diagonally up
        if (direction) {
          TLine[i]=new PVector(p2.x=p1.x+diagonals[i/2], p2.y=p1.y+diagonals[i/2]);
        }
        //If we're going diagonally down
        else {
          TLine[i]=new PVector(p2.x=p1.x+diagonals[i/2], p2.y=p1.y-diagonals[i/2]);
        }
        horizontal=true;
      }
    }
  }


  void drawLines() {
    for (int i=1;i < TLine.length;i++) {
      stroke(0);
      line(TLine[i-1].x, TLine[i-1].y, TLine[i].x, TLine[i].y);
    }
  }

  void drawPoint() {
    //Draw Point setup
    PointLocation=new PVector(TLine[0].x, TLine[0].y);
    PVector dir=PVector.sub(TLine[step], TLine[step+1]);
    dir.normalize();
    dir.mult(-0.5);
    acceleration=dir;

    velocity.add(acceleration);
    PointLocation.add(velocity);
    stroke(255, 0, 0);
    point(TLine[0].x, TLine[0].y);
    stroke(0, 255, 0);
    point(PointLocation.x, PointLocation.y);
    if (PointLocation.x>TLine[step+1].x) {
      println("PointLocatoin.x="+PointLocation.x+", Pointlocation.y="+PointLocation.y);
      PointLocation=(TLine[step]);
      step++;
    }
  }
}

Thanks, Tim

Tagged:

Answers

  • Hi! I don't know why the 1 pixels offset is happening. I would use lerp() to get a point between two other points, instead of using PVector.

    About the error at the end: the program increases step++ but does not check if TLine[step+1] is out of bounds.

    Maybe something like this?

      float substep = 0;
      float pixelsPerFrame = 0.5;
      void drawPoint() {
        if(step+1 == TLine.length) {
          println("DONE");
          noLoop();
          return;
        }
        
        stroke(255, 0, 0);
        point(TLine[0].x, TLine[0].y);
        
        float x = lerp(TLine[step].x, TLine[step+1].x, substep);
        float y = lerp(TLine[step].y, TLine[step+1].y, substep);
        
        stroke(0, 255, 0);
        point(x, y);    
        
        // divide the step size by the amout of pixels between two points (distance)
        substep += pixelsPerFrame / dist(TLine[step].x, TLine[step].y, TLine[step+1].x, TLine[step+1].y);
        if(substep > 1) {
          substep = 0;
          step++;
        }
      }
    
  • Thanks for this :)

    The end of array step was very useful.

    I'm using PVector because I'm studying Dan Shiffman's Nature of Code which relies heavily on PVector and also because I'm planning on making something more complicated with forces involved. It was nice to be able to de-construct your code to see another solution to the problem.

    As I said I'd like to figure out why the points can be off by 1 or 2 pixels. I just can't work out how they both get the data from the same array but can be in different locations once displayed on screen. Could it be a rounding error?

    Thanks

  • Even though drawing functions accept float data-type, in the end, pixel coordinates are whole values! @-)
    So, a fractional value gotta be rounded internally by them!

Sign In or Register to comment.