Loading...
Logo
Processing Forum
This particular example is using toxiclibs, but could just as easily be done using PVector, so I wasn't sure whether to place this in Programming Questions or Contributed Library Questions.

Anyways, onto the question:

Below is code to generate a path from (0, height) to an unknown destination. I was trying to use the highlighted line to steer the path towards the target Vector2D  t, but it doesn't prove to be reliable.

Copy code
  1. import toxi.geom.Vec2D;
  2. import toxi.math.noise.PerlinNoise;

  3. PerlinNoise n;
  4. Vec2D   p, pp, t;
  5. float   noiseScale = 300,
  6.         noiseStrength = 10,
  7.         stepSize = 5,
  8.         angle;
  9. boolean atTarget = false;

  10. void setup() {
  11.   size(800, 600);
  12.   smooth();
  13.   setPerlinNoise();
  14. }

  15. void draw() {
  16.   
  17.   stroke(0);
  18.   fill(255);
  19.   if(!atTarget) {
  20.     pp.set(p);
  21.     
  22.     angle = n.noise(p.x/noiseScale, p.y/noiseScale) * noiseStrength;
  23.     
  24.     // Create our FlowField position
  25.     p.addSelf(cos(angle) * stepSize * 3,
  26.               sin(angle) * stepSize * 3);
  27.     
  28.     // Steer towards our destination
  29.     p = p.interpolateToSelf(t, .1);
  30.     
  31.     // Draw where we've been
  32.     ellipse(p.x, p.y, 5, 5);
  33.     line(pp.x, pp.y, p.x, p.y);
  34.     
  35.     // Check to see if we're within target
  36.     if(abs(t.x - p.x) < 25 && abs(t.y - p.y) < 25) {
  37.       atTarget = true;
  38.     }
  39.   }
  40. }

  41. // Click to reset
  42. void mouseReleased() {
  43.   setPerlinNoise();
  44. }

  45. void setPerlinNoise() {
  46.   
  47.   background(255);
  48.   
  49.   // Reset variables
  50.   p  = new Vec2D(0, height);
  51.   pp = new Vec2D(p.x, p.y);
  52.   t  = new Vec2D(width/2, height/2);
  53.   n  = new PerlinNoise();
  54.   
  55.   atTarget = false;
  56.   
  57.   p.set(0, height);
  58.   n = new PerlinNoise();
  59.   
  60.   // Draw our target region
  61.   noStroke();
  62.   fill(255, 200, 0);
  63.   ellipse(t.x, t.y, 50, 50);
  64. }
Is there a way to get the path to hit the target 100% of the time? Perhaps I don't fully understand  interpolateToSelf() and   interpolateTo() . Well more precisely, I don't fully understand the difference between those two methods. Maybe the problem lies there?


http://jonobr1.com/

Replies(3)

What the interpolate methods do is to gradually move your vector to the target vector by a factor of 0 < n < 1 on every step, so for example you specify the target vector, then you specify the factor which will dictate how many steps will take to get to the destination, if you choose 1.0 the vector will jump to the target in 1 step along the way but if you select 0.5 the vector will move to half the distance to its target, them will move half of the remaining distance and the process continue until it reach its target, 

Run the following code and play with the factor value (line 33) to get the idea

Copy code
  1. import toxi.geom.Vec2D;
  2. import toxi.math.noise.PerlinNoise;

  3. PerlinNoise n;
  4. Vec2D   p, pp, t;
  5. float   noiseScale = 300,
  6.         noiseStrength = 10,
  7.         stepSize = 15,
  8.         angle;
  9. boolean atTarget = false;

  10. void setup() {
  11.   size(320, 240);
  12.   smooth();
  13.   setPerlinNoise();
  14. }

  15. void draw() {
  16.   
  17.   stroke(0);
  18.   fill(255);
  19.   if(!atTarget) {
  20.     pp.set(p);
  21.     
  22.     /*
  23.     angle = n.noise(p.x/noiseScale, p.y/noiseScale) * noiseStrength;
  24.     
  25.     // Create our FlowField position
  26.     p.addSelf(cos(angle) * stepSize, sin(angle) * stepSize);
  27.     */
  28.     
  29.     // Steer towards our destination
  30.     p = p.interpolateTo(t, 0.5);
  31.     
  32.     // Draw where we've been
  33.     line(pp.x, pp.y, p.x, p.y);
  34.     ellipse(p.x, p.y, 5, 5);
  35.     
  36.     
  37.     // Check to see if we're within target
  38.     if(dist(p.x, p.y, t.x, t.y) < 25) {
  39.       atTarget = true;
  40.       println( "at target" );
  41.     }
  42.   }
  43. }

  44. // Click to reset
  45. void mouseReleased() {
  46.   setPerlinNoise();
  47. }

  48. void setPerlinNoise() {
  49.   
  50.   background(255);
  51.   
  52.   // Reset variables
  53.   p  = new Vec2D(0, height);
  54.   pp = new Vec2D(p);
  55.   t  = new Vec2D(random(width/2, width), random(0, height));
  56.   n  = new PerlinNoise();
  57.   
  58.   atTarget = false;
  59.   
  60.   p.set(0, height);
  61.   n = new PerlinNoise();
  62.   
  63.   // Draw our target region
  64.   noStroke();
  65.   fill(255, 200, 0);
  66.   ellipse(t.x, t.y, 50, 50);
  67. }

Now the problem we have here is that the angle is distorting the p vector too much and it will never reach the target, the times it does is just by luck, Im very interested in solving this problem, so I will post any progress when I get a chance

Cheers

- rS

Your example is relying on 2 separate forces which need to be combined in a balanced way. In your case you manipulated the position directly and once you get closer to the target, the target attraction is simply not strong enough anymore to have any impact against the noise() based counter force. 

For example: You used interpolateToSelf() with a 0.1 value meaning you approach the target pos only by 10% of the current distance. As your distance shrinks so does the change amount. On the other hand your noise dir always moves as a fixed speed regardless of distance to the target -> BAD combination! :)

Below is an updated version of the draw() function showing a better/correct way:
Copy code
  1. // udpated these 2 params
  2. float noiseScale = 10;
  3. float noiseStrength = TWO_PI;

  4. void draw() {
  5.   stroke(0);
  6.   fill(255);
  7.   if(!atTarget) {
  8.     pp.set(p);
  9.     
  10.     // compute flow direction based on pos in noise space
  11.     angle = n.noise(p.x*noiseScale, p.y*noiseScale) * noiseStrength;
  12.     Vec2D flowDir=Vec2D.fromTheta(angle);

  13.     // and direction to target
  14.     Vec2D targetDir=t.sub(p).normalize();

  15.     // now combine forces in a 50:50 ratio
  16.     // reducing the interpolation factor below 0.5 will NOT guarantee
  17.     // that the target is ever being reached
  18.     // any value >0.5 means the target attraction is stronger than the flow dir
  19.     Vec2D dir=flowDir.interpolateTo(targetDir,0.5);

  20.     // normalize to step size and update position
  21.     p.addSelf(dir.normalizeTo(stepSize * 3));
  22.     
  23.     // Draw where we've been
  24.     ellipse(p.x, p.y, 5, 5);
  25.     line(pp.x, pp.y, p.x, p.y);
  26.     
  27.     // Check to see if we're within target
  28.     if(p.distanceTo(t) < 25) {
  29.       atTarget = true;
  30.     }
  31.   }
  32. }

This makes so much more sense when thinking about ratios of directions! I was thinking that because interpolateTo was following the noise it would always move 10% closer to the target effectively bringing the p closer to t every frame. Thanks very much, both @nardove and @toximeister, for the explanations.

@toximeister, is there a way to get the source of toxiclibs other than the mercurial repo?


http://jonobr1.com/