Loading...
Logo
Processing Forum
I want to keep drawing lines from the last point to the next point -- the next point is randomly chosen (Brownian movement) but I woud like to be able to control the length of the line, say have each line be 80 points long. I'm no math prodigy and I can't seem to find the right functions to look at. Here's the functioning code:

Copy code
  1.   point (x, y);
  2.   fill(255,0,0); // make a red circle around each node
  3.   ellipse(x,y, 8,8);
  4.   ex = int(random(0, rangex));
  5.   ey = int(random(0, rangey));
  6.   stroke(4,216,52);  // green line
  7.   line(x, y, ex, ey);

I want the set the distance of the line which is drawn from x,y to ex, ey.

You can see the line drawing in operation here:

http://www.borderlinegeek.com/big-data.htm

Thanks much for any help.


Replies(21)

You have to 'normalize' the vector between point A and B...

See:
http://processing.org/tutorials/pvector/

Good luck!

Rolf

Processing 2.0 also has methods that return random unit length vectors that can then be multiplied by the range.

Snippet
Copy code
  1. float range = 50;
  2. PVector e = PVector.random2D();
  3. e.mult(range);
  4. println(e);
  5. println(e.mag());
Okay!Thanks! I will study up on Pvector. And come back later to report.

Many thanks to both of you.
Clair

All right. I'm back. With the good, the bad, and the weird.

Understanding the vector idea was pretty straightforward. I now have exactly what was running before, except that now my coordinates are PVectors. And I learned a lot. BUT, when I tried to exercise any control over what were now obviously vector variables I was thoroughly stumped. I figure 9 hours work on one thing with no glimmer of success, it's time to ask for help again. Here's the code which works as you can see from the screen shot. And problem is described below that.


Copy code
  1. float x = random(300.0);
  2. float y = random(240.0);
  3. float ex;
  4. float ey;
  5. PVector startline;
  6. PVector endline;
  7. int width = 600;
  8. int height = 480;
  9. float m;
  10. //******************
  11. void setup() {
  12.  
  13.   size(width, height);
  14.   randomSeed(0);
  15.   background(0);
  16.   stroke(255);
  17.   frameRate(1);
  18.   startline=new PVector(x,y);
  19. }
  20. void draw() {
  21.   ex = random(width);
  22.   ey = random(height);
  23.   endline=new PVector(ex,ey);
  24.   println("startline magnitude = " + m);
  25.   if ((startline.x > width) || (startline.x < 0)) {
  26.     endline.x = endline.x * -1;
  27.   }
  28.   if ((startline.y > height) || (startline.y < 0)) {
  29.     endline.y = endline.y * -1;
  30.   }
  31.   println("startline.x = " + startline.x + " startline.y = " + startline.y);
  32.   println("endline.x = " + endline.x + " endline.y = " + endline.y);
  33.  
  34.  //////////////////////**********************////////////////////////////////// 
  35.  // m=startline.mag();
  36.  // endline.normalize();
  37.  // endline.mult(120);
  38.  //--------------------------------------------------------------------------- 
  39.  // m=startline.mag();
  40.  // startline.normalize();
  41.  // startline.mult(120);
  42.  //////////////////////**********************//////////////////////////////////
  43.   ellipse(startline.x,startline.y,8,8);
  44.   line(startline.x,startline.y, endline.x,endline.y);
  45.   startline=new PVector(endline.x,endline.y);
  46. }
Whenever I tried to insert any of the functions which I think I need, and want to test, lines are no longer connected or they are connected but bunched along a partial diameter of a circle with the dots seeming to appear in correct spots elsewhere in the box, etc.  I simply cannot figure out where these statements should be used. (You can see them in the big commented section.)

I understand that normalize creates a point from which a vector can be extended. And that the mult(120) should make that one point extend along the vector for 120 more points. Nothing vaguely resembling this happens. (I've learned a lot, but obviously not enough!)

Appreciate help, very much.
Clair

Perhaps this method of randomly placing a point would be useful:  http://processing.org/tutorials/trig/

Say you have a starting point and you know where it is. Then you can use cos() and sin() to pick a direction from that point. After you have a direction you pick a length (radius) and place a point in that direction at that length.

You can use a random range of directions (angles or radians) as well as a random range of lengths if you like. In the code below, the mouse's x position is mapped to a circular motion and the length is randomized:
Copy code
  1. float initialX, initialY;

  2. void setup() {
  3.   size(600, 600);
  4.   initialX = width/2;
  5.   initialY = height/2;
  6. }

  7. void draw() {
  8.   background(255);
  9.   ellipse(initialX, initialY, 10, 10);
  10.   
  11.   // Interactive direction based on mouse's x position
  12.   float theta = map(mouseX, 0, width, 0, TWO_PI);
  13.   
  14.   // Random length
  15.   float randomLength = random(100, 300);
  16.   
  17.   // Use the direction and random length to place a point
  18.   float x = initialX+cos(theta)*randomLength;
  19.   float y = initialY+sin(theta)*randomLength;
  20.   
  21.   // See it
  22.   ellipse(x, y, 10, 10);
  23.   line(initialX, initialY, x, y);
  24. }
Another code example...
Copy code
  1. PVector p = new PVector();
  2.  
  3. void setup() {
  4.   size(600, 600);
  5.   mousePressed();
  6.   stroke(255);
  7. }
  8.  
  9. void draw() {
  10.   if (frameCount % 4 == 0) { filter(BLUR); }
  11.  
  12.   PVector n = PVector.random2D();
  13.   n.mult(25);
  14.   n.add(p);
  15.  
  16.   line(p.x, p.y, n.x, n.y);
  17.   fill(255);
  18.   ellipse(n.x, n.y, 5, 5);
  19.  
  20.   p = n;
  21. }
  22.  
  23. void mousePressed() {
  24.   background(0);
  25.   p.set(width/2, height/2, 0);
  26. }
Hi asimes --
I ran your sketch and the one on the trig tutorial page -- and both examples are like all the other examples I've found -- they all maintain a fixed start point. I mucked about with both for the last half hour without any appreciable success. My startpoint needs to become the endpoint of a line just drawn, and once there, I start over with a new random endpoint. Each line starts from the end point of the previous line, going off in a randomly chosen direction.

And, with doing that I never did have any problems. The only problem came when I decided that I wanted my drawn line to be a fixed length each time. And all the examples I've been able find use, as I said a fixed point and they extend from that point in random directions. So, it seems that using a shifting startpoint WITH a fixed line length is nasty!!

Anyway, I will keep messing about because, for artistic reasons I really do want to solve this. Plus it would be a nice thing to know!

Thanks much for introducing me to the trig page, but right now, that is quite far beyond me (A.B.D. in British Lit.!!!)

Cheers

I'm not sure what you mean, you could randomly place a starting point if you wanted to and still use it to place a random endpoint in a random direction. That endpoint could be used as a starting point for the next one. All you would have to keep track of is what the current starting point is (it will be assigned to be the last endpoint every time).

This is actually the same idea as what amnon.owed did. The random2D() is the same concept as using cos() and sin() to pick a direction (but with vectors). The mult(25) is the length (radius) from the starting point. p = n is the same as making the staring point the end point.

Edit: I modified the code to do this below, if the first code made sense then hopefully doing the mental gymnastics to see how this is the same should be easy:
Copy code
  1. float initialX, initialY, endX, endY;

  2. void setup() {
  3.   size(600, 600);
  4.   initialX = width/2;
  5.   initialY = height/2;
  6. }

  7. void draw() {
  8.   ellipse(initialX, initialY, 10, 10);

  9.   // Random direction
  10.   float theta = random(TWO_PI);

  11.   // Random length
  12.   float randomLength = random(10, 30);

  13.   // Use the direction and length to place a point
  14.   endX = initialX+cos(theta)*randomLength;
  15.   endY = initialY+sin(theta)*randomLength;

  16.   // See it
  17.   ellipse(endX, endY, 10, 10);
  18.   line(initialX, initialY, endX, endY);
  19.   
  20.   // Set initial point as end point
  21.   initialX = endX;
  22.   initialY = endY;
  23. }
WAHOOOOOOOOO amnon!!

You did it - I wil study this code until it is etched in my brain and also compare it to what I was trying to do, to see where I went wrong --

Thank you so much.

What I find interesting is that I didn't need to use magniture or normalize at all. I'm now going try to understand exactly how mult and add and random2D work. I can't tell you have relieved I am to have something concrete which works that I can break down into pieces.

And, BTW, after I quit working on all of this yesterday, I spent at least an hour on your blog. And have bookmarked it for future investigation.
Ok, great. Note for future reference that the same technique can be applied to 3D as well...

Code Example (3D brownian motion)
Copy code
  1. ArrayList <PVector> points = new ArrayList <PVector> ();
  2. PVector c = new PVector();
  3.  
  4. void setup() {
  5.   size(1280, 720, P3D);
  6.   smooth(16);
  7.   colorMode(HSB, 500, 100, 100);
  8.   points.add( new PVector() );
  9.   strokeWeight(1.5);
  10.   noFill();
  11. }
  12.  
  13. void draw() {
  14.   background(0);
  15.   perspective(PI/3.0, (float) width/height, 1, 1000000);
  16.  
  17.   // interpolated rotating camera aimed at last point
  18.   PVector lp = points.get(points.size()-1).get();
  19.   lp.mult(0.01);
  20.   c.mult(0.99);
  21.   c.add( lp );
  22.   camera(c.x+sin(frameCount*0.01)*1500, c.y+cos(10+frameCount*0.008)*1500, c.z-1500,
  23.     c.x, c.y, c.z,
  24.     0, 1, 0);
  25.  
  26.   // colored curved lines
  27.   int index=0;
  28.   beginShape();
  29.   for (PVector p : points) {
  30.     stroke((++index+frameCount)%500, 100, 100);
  31.     curveVertex(p.x, p.y, p.z);
  32.   }
  33.   endShape();
  34.  
  35.   // new point at specified range
  36.   PVector n = PVector.random3D();
  37.   n.mult(100);
  38.   n.add(points.get(points.size()-1));
  39.   points.add( n );
  40.  
  41.   // if too slow, start removing points
  42.   if (frameRate < 55) { points.remove(0); }
  43. }
Yes, when I read about add it said x,y,z which I knew to be the 3D coordinates and I assumed (bad of me I know to assume anything) that this was a function which took either 2 or 3 parameters.

I'm working now on constraining the little beggars to the box because right now they sometimes go off into the void, never to return. But, this I know I can do!!!

To show you that I can actually get somewhere -- I did this one last year, if you watch it for bit, it gets quite a lot of depth to it:

http://www.vt2k.com/processing/recession.htm

an hour later: curse you amnon --

 I just wanted to take a break from working so I decided to load your Brownian 3D -- I am no longer happy with my 2D version!!!

I am going to show this to people and take the liberty of saying "my friend amnon made this!".

Processing is not only a language, in the right hands it can be an inspiration -- thank you.

This is one of the most beautiful creations I have seen in Processing.
I've toyed w/ both of them and did some tiny tweaks while trying to study them. Here they are: 

Copy code
    // https://forum.processing.org/topic/
    // controlling-the-length-of-line-from-x-y-to-a-point-which-is-randomly-chosen
    
    final PVector p = new PVector(), n = new PVector();
    final static int DIM = 5, LEN = 30;
    
    void setup() {
      size(1200, 800);
      stroke(-1);
      fill(-1);
    
      mousePressed();
    }
    
    void draw() {
      if ((frameCount & 0xF) == 0)   filter(BLUR);
    
      PVector.random2D(n).mult(LEN);
      n.add(p);
    
      line(p.x, p.y, n.x, n.y);
      ellipse(n.x, n.y, DIM, DIM);
    
      p.set(n);
    
      frame.setTitle("FPS: " + round(frameRate));
    }
    
    void mousePressed() {
      background(0);
      p.set(width>>1, height>>1);
    }
    




Copy code
    /** 
     * Brownian Motion (v2.11)
     * by Ammon.Owed (2013/Aug)
     * mod GoToLoop
     * 
     * http://forum.processing.org/topic/
     * controlling-the-length-of-line-from-x-y-to-a-point-which-is-randomly-chosen
     */
    
    import java.util.Deque;
    import java.util.ArrayDeque;
    
    final static int DIM = 100, MAX = 03000, DETAIL = 1000, DEPTH = 2000;
    final static int HUE = 0x200, FPS = 60, TOLERANCE = 40, ALIASING = 2;
    final static boolean HAS_MAX_LIMIT = true;
    
    final Deque<PVector> points = new ArrayDeque(MAX);
    final PVector cam = new PVector(), lp = new PVector();
    
    float canvasRatio;
    
    void setup() {
      size(1000, 700, P3D);
      frameRate(FPS);
      smooth(ALIASING);
      colorMode(HSB, HUE, 1, 1);
      strokeWeight(1.5);
      noFill();
    
      canvasRatio = (float) width/height;
    
      points.add(new PVector());
    
      frameRate = TOLERANCE<<1;
    }
    
    void draw() {
      // auxiliary local variables
      final int fc = frameCount, fr = round(frameRate);
      final PVector tmp = new PVector();
    
      // interpolated rotating camera aimed at last point
      lp.set(points.getLast());
      cam.mult(.99);
      cam.add(PVector.mult(lp, .01, tmp));
    
      background(0);
      perspective(THIRD_PI, canvasRatio, 1, 1e6);
    
      camera(cam.x + sin(fc*.01)*DETAIL, cam.y + cos(10 + fc*8e-3)*DETAIL, 
      cam.z - DEPTH, cam.x, cam.y, cam.z, 0, 1, 0);
    
      // colored curved lines
      int idx = 0;
      beginShape();
    
      for (PVector p: points) {
        stroke(fc + idx++ & HUE - 1, 1, 1);
        curveVertex(p.x, p.y, p.z);
      }
    
      endShape();
    
      if (HAS_MAX_LIMIT) {
        if (fc >= MAX)       points.remove();
      }
    
      else {
        if (fr < TOLERANCE)  points.remove();
      }
    
      // new point at specified range
      PVector.random3D(tmp).mult(DIM);
      tmp.add(lp);
      points.add(tmp);
    
    
      frame.setTitle("Brownian Motion\t\tFPS: " +fr+ "\t\tSize: " +points.size());
    }
    

I can't wait -- I just saw that you had added these but I have to get off for supper and the night.

Will be on them first thing tomorrow -- about 4.a.m.

Curse the forum -- or rather ZoHo -- I can't believe how long this thing was down!

Anyway -- GoToLoop -- I like the second one best. However, there is much in there which I don't understand (yet). Still, I will experiment with it.

HOWEVER -- and this to all of you -- yesterday my copy of Generative Design arrived. Just as I was thinking about how best to proceed in a directed study of where I want to work in processing. Perfect timing. This is just exactly the book I have been dreaming about.

So, I am saving GoToLoop last code and amnon's 3D for when I can better understand them (and use them!!!).

Thank you all so much!

I had posted some code that was an extension to my first one and does something similar to amnon.owed's 2D code. It was a comment, not a reply, was not sure if you had seen it because you said my first code was easy to follow.

If the first one was easy to follow the extension should be as well, it is just a different way to make a radius of length 1 around a point and then multiply it by a length. The only difference is that it uses cos() and sin() instead of the vector methods.

The advantage of amnon.owed's code has is that it generalizes to 3D more easily and should be a bit faster because it doesn't use trig functions.
I have just printed out both amnon's and your second sketch. I'm going to set them aside together to look at when I am more advanced. (However, I needn't set aside their beauty. Yours happens now to be running as I type.)

I will say, at first glance there is much I don't understand. But that is because all of this 3d stuff is I know way beyond me at this point, (my initial post was a beginner's question!) as it should be -- I am right now, working with Generative Design as  a program of study, for which it is exceedingly well-suited.

Thanks for jumping in and I look forward to more posts from you in the months ahead.

Cheers,
clair

asimes -- thank you -- It has been the weekend here and I had two lengthy appointments and have been away from the keyboard. I am back now and will be hard at it tomorrow morning--investigating everything more thoroughly.

BUT -- I realized -- rather late, that I had a mistake in my link above -- I have two servers vt2k and vt2000. I posted the wrong one. Here is the proper link to my Recession piece:

http://www.vt2k.com/processing/recession.htm

Apologies to all for the 404.
Man - this is nuts! I copied that link from the URL bar.

http://www.vt2k.com/processing/recession.htm

For some reason, not understood by me -- that link tacked on (at the front) my other website -- borderlinegeek.com. I think I just didn't use the chain icon when I stuck it there.

Interesting. BUT now thanks to Rolf -- both are correct and I will go back and correct the orginal one!

Algorithm: take paper towel
                crumple up
                hold in right hand
                raise hand to face
                vigorously wipe egg off
                end