Making lines converge to a point

Hi,
I’m working on my n-th mini project. I would like to have multiple parallel lines pointing to mouse position on a click. Here’s the code I wrote:

//introducing vectors
PVector vMouse, u, w;

//introducing arrays
//of integers, to store coordinates
int[] xA;
int[] yA;
int[] yB;

//and of vectors, to draw the lines
PVector[] v1;
PVector[] v2;

void setup() {
  size(640, 370);
  background(255);

  //setting arrays' length
  xA = new int[width/10];
  yA = new int[height/20];
  yB = new int[height/20];

  v1 = new PVector[xA.length];
  v2 = new PVector[xA.length];

  //setting x coordinates for the lines
  for (int i = 0, j = 0; i < width; i += 10) {
    xA[j] = i + 10;
    j++;
  }

  //setting a couple of y coordinates for the lines
  for (int i = 10, j = 0; i < height; i += 20) {
    yA[j] = i;
    yB[j] = i + 10;
    j++;
  }

  //based on coordinates previously set up,
  //I define a bunch of vectors
  for (int i = 0; i < width/10; i ++) {
    for (int j = 0; j < height/20; j++) {
      v1[i] = new PVector(xA[i], yA[j]);
      v2[i] = new PVector(xA[i], yB[j]);
    }
  }
}

void draw() {
  if (mousePressed == true) {
    background(255);
    
    //defining a vector going from origin to mouse position
    vMouse = new PVector(mouseX, mouseY);
    
    //using a for loop to cycle through the arrays of coordinates
    for (int i = 0; i < width/10; i ++) {
      for (int j = 0; j < height/20; j++) {
        
        //copying the vector going from origin to (xA, yB)
        u = v2[i].copy();
        //copying the mouse position vector
        w = vMouse.copy();
        //finding the difference between vectors:
        //u - v1
        u.sub(v1[i]);
        
        //finding the magnitude of u
        float m = u.mag();
        
        //finding the difference between vectors:
        //w - v1
        w.sub(v1[i]);
        
        //finding w's unit length
        w.normalize();
        
        //and multiplying it by u's magnitude
        //to have the same lengths
        w.mult(m);

        //then shifting the origin
        translate(v1[i].x, v1[i].y);
        //and drawing the line to the expected coordinates
        line(0, 0, w.x, w.y);
      }
    }
    
    //if mouse is not pressed
  } else {
    background(255);

    //I use a for cycle to go through the arrays of coordinates
    for (int i = 0; i < width/10; i ++) {
      for (int j = 0; j < height/20; j++) {
        //and draw the lines based on the coordinates
        line(xA[i], yA[j], xA[i], yB[j]);
      }
    }
  }
}

Now, it seems all ok except for the fact that only 1 line is pointing to mouse position (by the way, why just that line on the lower left??). I guess the point is on lines 82 to 85

        //then shifting the origin
        translate(v1[i].x, v1[i].y);
        //and drawing the line to the expected coordinates
        line(0, 0, w.x, w.y);

where I shift the origin to draw the lines; I can’t figure out how to make the lines simultaneously rotate towards mouse position. Any idea?

HI,
you re really close (;
problem is certainly in the part of code you highlight:
if you compare inside the loop for mousepressed or not, there is a major difference
unpressed you just draw lines, mouse pressed you move inside you drawing area with translate before every line
(good news is certainly all your lines are draw but certainly out of screen)

two ways to fix that, or remove this translate mouvement and draw as when mouse is unpressed, or a good oportunity to play with pushMatrix(); / popMatrix

Hi,

The translate() function is cumulative, so if you call it several times in a row it just adds up on top of each other so most of your line are drawn out of the screen space.

To avoid this, use the push() and pop() functions. They act like save and load functions: push() save the current transformation matrix and pop() restore the transformation matrix.

In practice, if you wrap your translate() in between them, it won’t add up the transformation:

...

push();
translate(v1[i].x, v1[i].y);
pop();

...

Although in your case it does not completely solves your issue.

To be honest I had a hard time going through your code and instead of deep diving into it I thought about sharing a piece of code that does exactly the same thing but, I think, in a simpler manner. I hope it can be useful to you:

//Parameters
final int nbOfCols = 64;
final int nbOfRows = 16;
final int lineLen = 10;


//Helping variables
float xSpacing, ySpacing;


void setup() {
  size(640, 370);

  //Compute the spacing in the x and y directions
  xSpacing = (float)width / (nbOfCols + 1);
  ySpacing = (float)height / (nbOfRows + 1);
  
  //Set the style
  stroke(225);
  strokeWeight(1);
}


void draw() {
  background(20);
  
  
  //Loop through each columns and row
  for (int i = 0; i < nbOfCols; i++) {
    for (int j = 0; j < nbOfRows; j++) {
      //Find the center of the segment
      float cx = (i + 1) * xSpacing;
      float cy = (j + 1) * ySpacing;
      
      //Call drawLine function with or without a target point depending if mouse is pressed or not
      if (mousePressed) {
        drawLine(cx, cy, new PVector(mouseX, mouseY));
      } else {
        drawLine(cx, cy, null);
      }
    }
  }
}


void drawLine(float cx, float cy, PVector toPoint) {
  //If mouse is not pressed, lines are verticals so the angle should be PI/2 (angle 0 is vector pointing right)
  float angle = HALF_PI;
  
  //If a target point is defined, find the angle from the center of the line to draw to the target point
  if (toPoint != null) {
    PVector dir = new PVector(toPoint.x - cx, toPoint.y - cy);
    angle = dir.heading();
  }
  
  
  //Translate and rotate as needed
  push(); //DO NOT FORGET
  translate(cx, cy);
  rotate(angle - HALF_PI);
  
  //Draw the line
  line(0, -lineLen / 2.0, 0, lineLen / 2.0);
  pop(); //DO NOT FORGET
}
2 Likes