Adjusting a sample of positions by interpolation. Perfect shape and movement

Hi everyone!
I’m trying to make a movement repeating himself by adapting the end with the beginning of the movement.
For example I try to draw a circle or the shape " 8 " during an elapsed time.
I would like to have one interpolation between the two last positions X and Y with the two first positions X and Y in order to not have a big space between last and first positions.
In my program, try to make the shape " 8 " in a period of 2 sec, the drawing will be record between measure 2 and 4 and automatically after the draw will repeat it self

Thanks for your help.

int actualSec,lastSec,measure;
boolean bRecording = false;
boolean mouseRecorded =  true;
class Sample {
  int t, x, y;
  Sample( int t, int x, int y ) {
    this.t = t;  this.x = x;  this.y = y;
  }
}
class Sampler {
  ArrayList<Sample> samples;
  int startTime;
  int playbackFrame;
  Sampler() {
    samples = new ArrayList<Sample>();
    startTime = 0;
  }
  void beginRecording() {
    samples = new ArrayList<Sample>();
    playbackFrame = 0;
  }
  void addSample( int x, int y ) {
    int now = millis();
    if( samples.size() == 0 ) startTime = now;
    samples.add( new Sample( now - startTime, x, y ) );
  }
  int fullTime() {
    return ( samples.size() > 1 ) ? 
      samples.get( samples.size()-1 ).t : 0;
  }
  void beginPlaying() {
    startTime = millis();
    playbackFrame = 0;
    println( samples.size(), "samples over", fullTime(), "milliseconds" );
  }
  void draw() {
    stroke( 255 );
    beginShape(LINES);
    for( int i=1; i<samples.size(); i++) {
      vertex( samples.get(i-1).x, samples.get(i-1).y );
      vertex( samples.get(i).x, samples.get(i).y );
    }
    endShape();
    int now = (millis() - startTime) % fullTime();
    if( now < samples.get( playbackFrame ).t ) playbackFrame = 0;
    while( samples.get( playbackFrame+1).t < now )
      playbackFrame = (playbackFrame+1) % (samples.size()-1);
    Sample s0 = samples.get( playbackFrame );
    Sample s1 = samples.get( playbackFrame+1 );
    float t0 = s0.t;
    float t1 = s1.t;
    float dt = (now - t0) / (t1 - t0);
    float x = lerp( s0.x, s1.x, dt );
    float y = lerp( s0.y, s1.y, dt );
    circle( x, y, 10 );
  }
}
Sampler sampler;
void setup() {  
  size( 800, 800, P3D );
  frameRate( 30 );  
  sampler = new Sampler();
}
void draw() {
  activeSampling();
  stopSampling();
  
     if  (actualSec!=lastSec){
         lastSec=actualSec;
         measure++;
     }
         actualSec =(int) (millis()*0.001);  // 
  background( 0 );
  if( bRecording ) {
    circle( mouseX, mouseY, 10 );
    sampler.addSample( mouseX, mouseY );
  } else {
    if( sampler.fullTime() > 0 )
        sampler.draw();
  }
}
void mousePressed() {
  mouseRecorded = true;
  }
void activeSampling() { 
   if (measure<=2 && measure>=2 &&actualSec!=lastSec && mouseRecorded == true) {
  bRecording = true;
  sampler.beginRecording();
  }
}
void stopSampling() { 
   if (measure<=4 && measure>=4  && actualSec!=lastSec) {
  mouseRecorded = false;
  bRecording = false;
  sampler.beginPlaying();
  }
}

1 Like

Hi @bking,

From what I understand, you want to close the whole drawing by connecting the end of the drawing to the beginning of the drawing is that right?

If so, you just need to add a new Sample to the samples list that is the first sample in the list, like:

samples.add(samples.get(0));
1 Like

Thanks for trying to help me!

If you try to draw an ‘8’ as soon as you run the sketch, the shape ‘8’ is recorded and this shape repeats itself. But a line between the end and the begin of the shape will miss. So I have to create a point between the first and the last point.

1 Like

The moment you call stopSampling() and the conditions in there are met, you could calculate the distance between the start- and end point and add steps in between. Depending on the distance between those points you could add a certain amount of steps, so it looks like a smooth motion.

Also, you can simplify these conditions:

measure<=2 && measure>=2
// ...
measure<=4 && measure>=4
1 Like

603 / 5 000

Résultats de traduction

star_border

That’s exactly what I’m trying to do and I’m not a good programmer at all. In fact, I only need one coordinate that repeats itself but I think my question is easier to understand in two dimensions. Ideally, I would like to add a point between the last and the first point recorded in order to have a regular, fluid movement. By calculating the average or by extrapolating several points between the last and the first points recorded. I think it’s difficult, I’m looking for an engineer to help me, but I don’t know where to find one.

Do you mean you want the sketch to complete the (incomplete) drawn path so it looks like the user drew a full shape in a singular, swift motion? And then to that completed part add points based on the user’s recorded mouse movement speed?

I tried to visualize it to see if I understand you correctly. Is the image below kind of what you have in mind?

3 Likes

Hi Tiemen,
It’s exactly what I would love to have! :slight_smile: :kissing_heart:

That indeed sounds like a difficult —yet awesome!— problem to solve. I’d start by dividing the entire problem into smaller, easier to manage chunks. At this point it doesn’t seem like you’re stuck on the programming, but rather on understanding the inner workings behind it.

For instance, how would automatic path completion work? For each path that I draw there are multiple ways to auto complete it, as shown in the image below (1). I’d say it all comes down to how you, as the designer of the system, decide to calculate it.
And what happens when the path becomes insanely complicated (2)? Does the automatic path completion copy (part of) that complexity, or do you put a restriction on it and say something like: “The auto completed path between the start- and end point is either a straight line, a (slightly) curved line, or an S shaped line.”

So again, break it up it smaller parts and solve those one at a time. Sketch it on paper, and once you have an idea of how it should work, then try realizing it in Processing. Once you figured out how to design all the smaller parts, bring them together in Processing.

For the automatic path completion it might be worth your while to dive into the inner workings of beziers (Processing has various bezier methods methods you can use, such as this one).
You could also look into The Nature of Code, where Pvectors are used to calculate new positions based on velocity and whatnot.

Hope that helps. Good luck!

1 Like

Hi,
I have seen in your last link a sketch to calculate the acceleration between two points. Maybe it would be nice to calculate a “virtual acceleration” between the last and the first recorded points and the program will itself calculate the direction and speed of the created vector? Do you think this could be a good method? Will my movement repeat for another 2 bars? Here is the program following mouse Y. I tried saving a pointY from the old frame point of mouseY and calculating an acceleration to create movement between but I’m not sure if that works. Like I said, I only need to do mouseY or mouseX sampling, so I don’t need to create a bezier curve. I guess it might be simple to do for you or another engineer I could pay. I have a lot to do to show my project before the deadline :face_in_clouds: I’ll post another topic tomorrow for another move I’m trying to make. Thank you for your understanding and your possible help.

// An array of objects
Mover[] movers = new Mover[1];

int formerFrameCount, lastMouseX, lastMouseY;

void setup() {
  size(640,360);
  background(255);
  for (int i = 0; i < movers.length; i++) {
    // Initialize each object in the array.
    movers[i] = new Mover();
    mouseY= 180;
  }
}

void draw() {
  formerFrameCount  =  frameCount%2;
  if ( formerFrameCount <=0)  {
      lastMouseX= height/2;
      lastMouseY= mouseY;
    }
    
  print ( "mouseY " +  mouseY, lastMouseY);
  background(255);

  for (int i = 0; i < movers.length; i++) {
    //[full] Calling functions on all the objects in the array
    movers[i].update();
    movers[i].checkEdges();
    movers[i].display();
    //[end]
  }
}

class Mover {

  PVector location;
  PVector velocity;
  PVector acceleration;
  float topspeed;

  Mover() {
  //  location = new PVector(random(width),random(height));
    location = new PVector(width/2, lastMouseY); // lastMouseY
    velocity = new PVector(0,0);
    topspeed = 10;
  }

  void update() {

    // <b><u>Our algorithm for calculating acceleration</b></u>:

    //[full] Find the vector pointing towards the mouse.
    PVector mouse = new PVector(width/2, mouseY);  //lastMouseY
    PVector dir = PVector.sub(mouse,location);
    //[end]
    // Normalize.
    dir.normalize();
    // Scale.
    dir.mult( 1+ abs ( mouseY - lastMouseY )  ); // height/2
  
    // Set to acceleration.
    acceleration = dir;

    //[full] Motion 101! Velocity changes by acceleration.  Location changes by velocity.
  //  velocity.add(acceleration);
  velocity.add(acceleration);
    velocity.limit(topspeed);
    location.add(velocity);
    //[end]
  }

  // Display the Mover
  void display() {
    stroke(0);
    fill(175);
    ellipse(location.x,location.y,16,16);
  }

  // What to do at the edges
  void checkEdges() {
   println ( " locationY " ,   location.y);
    if (location.x > width) {
      location.x = 0;
    } else if (location.x < 0) {
      location.x = width;
    }

    if (location.y > height) {
      location.y = 0;
   
    }  else if (location.y < 0) {
      location.y = height;
    }
  }
}

Yeah that might work, sounds promising! And good to see you’ve experimented with it in a sketch.

I’m going to experiment some on my own tomorrow and see if it’s easy to realize. If so, you can repay me by making a modest donation to the Processing Foundation (or any other good cause to your liking).

2 Likes

Great ! Great idea, I just made a donation ;).
The program to interpolate the points between them and create a fluid motion was made by Scudly. He was very nice to me too.
I have a lot of pattern to create to find interesting moves, I hope many engineers will help me again and again! I really like the open source philosophy.
Thanks a lot. Benjamin from Bordeaux FRANCE :saluting_face: :sunglasses: :grinning: :grin:

1 Like