Create an intermediate point

Hello all!

For an artistic project, I sample for two seconds a pseudo circle (not entirely finished) drawn with the mouse.
Then this shape repeats itself.

I would like to add between the last and the first point drawn, “an interpolation point” or more simply an intermediate point which is placed at the average
of the affine line created by the first and the last.

To draw a pseudo circle over two seconds, you have to keep the mouse pressed. The recording is done at each change of second.
(but we’re not supposed to know that).

Thanks for your help :wink:

int actualSec,lastSec,measure,measureToStartRecording;
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 ) {  // add sample when bRecording
    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 );
    
    //**RECORD
    beginShape(LINES);
    for( int i=1; i<samples.size(); i++) {
      vertex( samples.get(i-1).x, samples.get(i-1).y ); // replace vertex with Pvector
      vertex( samples.get(i).x, samples.get(i).y );
    }
    endShape();
    //**ENDRECORD
    
    //**REPEAT
    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() {
  background( 0 );
  activeSampling();
  stopSampling();
  
  if  (actualSec!=lastSec){
       lastSec=actualSec;
       measure++;
       textSize (100);
       text (measure, 100, 100 );
     }
       actualSec =(int) (millis()*0.001);  // 
 
  if( bRecording) { // draw circle
    circle( mouseX, mouseY, 10 );
    sampler.addSample( mouseX, mouseY );
  }
  
  else {    
  if( sampler.fullTime() > 0 )
        sampler.draw();
  }
}

void mousePressed() {
  bRecording = true;   // draw circle
  mouseRecorded = true;
  measure=0;
}
  
void activeSampling() { 
   if (measure<=1 && measure>=1 &&actualSec!=lastSec && mouseRecorded == true) {
  sampler.beginRecording();
  }
}

void stopSampling() { 
   if (measure<=3 && measure>=3  && actualSec!=lastSec) {  
  mouseRecorded = false;
     //**REPEAT
  bRecording = false;
  sampler.beginPlaying();
  }
}

I suggest to only add when

if( mouseX!=pmouseX ||
 mouseY!=pmouseY)

Regarding your question:

Isn’t the intermediate just the center between start and end, so the middle of the Arraylist? Just like
int (list.size() /2.0)

1 Like

I think he means to complete the circle so the mid point between start and and end is not the mid point of the list.

So this is homework? If so no full code solutions.

We need to find the start and last points drawn so let’s look at the mousePressed method

Now add a mouseReleased method

void mouseReleased() {
  // if we are recording i.e. bRecording is true then the mouse has just 
  // been released so we can store the end position for the curve
  // Now you have start and end positions the mid point between 
  // them can be added to the curve.
}
2 Likes

Hi,

Yes, maybe there is a command computing the middle of the last and the beginning of an arrayList.
Or something else computing the middle of a vector from the last and the beginning point.
Then it might be easy to add this point at the end of the array list.
But I really don’t know how to proceed.
Thank again for helping!

I add you code line 100 like that but the program doesn’t understand.

int actualSec,lastSec,measure,measureToStartRecording;;
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>();
    print (samples);
    playbackFrame = 0;
  }
  void addSample( int x, int y ) {  // add sample when bRecording
    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 );
    
    //**RECORD
    beginShape(LINES);
    for( int i=1; i<samples.size(); i++) {
      vertex( samples.get(i-1).x, samples.get(i-1).y ); // replace vertex with Pvector
      vertex( samples.get(i).x, samples.get(i).y );
    }
    endShape();
    //**ENDRECORD
    
    //**REPEAT
    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 );
    println (frameCount + " x " + x);
  }
  
}

Sampler sampler;

void setup() {  
  size( 800, 800, P3D );
  frameRate( 30 );  
  sampler = new Sampler();
}

void draw() {
 // text ( "bla" , 200, 200);
  background( 0 );
  activeSampling();
  stopSampling();
  
  if  (actualSec!=lastSec){
       lastSec=actualSec;
       measure++;
       textSize (100);
       text (measure, 100, 100 );
     }
       actualSec =(int) (millis()*0.001);  // 
 
  if( bRecording) { // draw circle
  //  circle( mouseX, mouseY, 10 );
    sampler.addSample( mouseX, mouseY );
   //*** Chisir Method 
 //  if( mouseX!=pmouseX || mouseY!=pmouseY) {   
 //  int (list.size() /2.0)
   }
  }
  
  else {    
  if( sampler.fullTime() > 0 )
        sampler.draw();    
  }  
}

void mouseReleased() {
  bRecording = true;   // draw circle
  mouseRecorded = true;
  measure=0;
}
  
void activeSampling() { 
   if (measure<=1 && measure>=1 &&actualSec!=lastSec && mouseRecorded == true) {
  sampler.beginRecording();
  }
}

void stopSampling() { 
   if (measure<=3 && measure>=3  && actualSec!=lastSec) {  
  mouseRecorded = false;
     //**REPEAT
  bRecording = false;
  sampler.beginPlaying();
  }
}

I think you’re right, the mid point is the average point between the last and the fist point of the array list.

I changed with mouseReleased() and it doesn’t change anything!

Thanks again.

Hi again!
How can we get the last and the first data of the arrayList?

Then I will have two add a point calculated like that


Thanks again

list.get(0)
and

list.get(list.size()-1)

Maybe even list.last()

I wrote this println ( " lastDataOfTheSample " + list.get(list.size()-1);
but I have syntax error.
Could you please put your lines of code in my code?

1 Like

here is an example

see last paragraph in draw() pls

you need to click two points with the mouse into my program



ArrayList<PVector> points = new ArrayList ();

boolean runPoints=false;

float x, y;
float startX, startY, endX, endY;
float timeSpan;

int i=0;

float amt;

void setup() {
  size(800, 800);
  startX = width/2;
  startY = height/2;
  endX = 100;
  endY = 100;
  timeSpan = 2000.0;
}

void draw() {

  if (runPoints) {
    // PLAY Mode

    // background(255);

    //   frameRate(1) ;
    fill(255, 0, 0);
    text("PLAY Mode - press any key to edit ", 19, 19);

    PVector pv1 = points.get(i);
    PVector pv2 = points.get(i+1);

    /// lerp !!!!!


    //for (int i2 = 0; i2 <= 10; i2++) {
    float x = lerp(pv1.x, pv2.x, amt/10.0);
    float y = lerp(pv1.y, pv2.y, amt/10.0);
    point(x, y);
    // }

    // line(pv1.x, pv1.y, pv2.x, pv2.y);

    amt+=0.1;
    if (amt>10) {
      amt=0;
      i++;
    }


    if (i>points.size()-2) {
      i=0;
      runPoints=false;
    }
  }//if
  else {
    // Edit mode
    background(255);

    fill(255, 0, 0);
    text("Edit Mode - click mouse points and press any key to play ", 19, 19);

    for (int i = 0; i<points.size(); i++) {
      PVector pv1 = points.get(i);
      ellipse(pv1.x, pv1.y, 4, 4);
    }
  }//else

  //-------
  // show first and last point
  if (points.size()>1) {
    fill(0);
    text("0", points.get(0).x, points.get(0).y-3);
    PVector pv = points.get(points.size()-1).copy();
    text("last", pv.x, pv.y-3);
  }//if
  //
}// function draw()

//-------------------------------------------------------------------

void mousePressed() {
  points.add(new PVector(mouseX, mouseY));
  runPoints=false;
}

void keyPressed () {
  // toggle runPoints
  runPoints =
    ! runPoints;
  if (runPoints) {
    background(255);
  }
}

your arraylist is called samples, not list

you also have a missing ) at the end

I am sure you can apply it to your code.

new version with println:



ArrayList<PVector> points = new ArrayList ();

boolean runPoints=false;

float x, y;
float startX, startY, endX, endY;
float timeSpan;

int i=0;

float amt;

void setup() {
  size(800, 800);
  startX = width/2;
  startY = height/2;
  endX = 100;
  endY = 100;
  timeSpan = 2000.0;
}

void draw() {

  if (runPoints) {
    // PLAY Mode

    // background(255);

    //   frameRate(1) ;
    fill(255, 0, 0);
    text("PLAY Mode - press any key to edit ", 19, 19);

    PVector pv1 = points.get(i);
    PVector pv2 = points.get(i+1);

    /// lerp !!!!!


    //for (int i2 = 0; i2 <= 10; i2++) {
    float x = lerp(pv1.x, pv2.x, amt/10.0);
    float y = lerp(pv1.y, pv2.y, amt/10.0);
    point(x, y);
    // }

    // line(pv1.x, pv1.y, pv2.x, pv2.y);

    amt+=0.1;
    if (amt>10) {
      amt=0;
      i++;
    }


    if (i>points.size()-2) {
      i=0;
      runPoints=false;
    }
  }//if
  else {
    // Edit mode
    background(255);

    fill(255, 0, 0);
    text("Edit Mode - click mouse points and press any key to play ", 19, 19);

    for (int i = 0; i<points.size(); i++) {
      PVector pv1 = points.get(i);
      ellipse(pv1.x, pv1.y, 4, 4);
    }
  }//else

  //-------
  // show first and last point
  if (points.size()>1) {
    fill(0);
    text("0", points.get(0).x, points.get(0).y-3);
    PVector pv = points.get(points.size()-1).copy();

    println(pv);
    println ( "lastDataOfTheSample "
      + points.get(points.size()-1) ) ;

    text("last", pv.x, pv.y-3);
  }//if
  //
}// function draw()

//-------------------------------------------------------------------

void mousePressed() {
  points.add(new PVector(mouseX, mouseY));
  runPoints=false;
}

void keyPressed () {
  // toggle runPoints
  runPoints =
    ! runPoints;
  if (runPoints) {
    background(255);
  }
}

2 Likes

Thanks. An engineer found a solution for me.
Here it is!
`But now I have to map this interpolation, just the interpolation of y, in order to have a variable from 0 to TWO to see a ball turning always in the same way! I hope you can keep to try to help me!

int actualSec,lastSec,measure,measureToStartRecording;
boolean bRecording = false;
boolean mouseRecorded =  true;

int nbBalls=1;

float movementInterpolated;


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;
  ArrayList<Sample> samplesModified;
  int startTime;
  int playbackFrame;
  
  Sampler() {
    samples = new ArrayList<Sample>();
        samplesModified = new ArrayList<Sample>();
    startTime = 0;
  }
  void beginRecording() {   
    samples = new ArrayList<Sample>();
    samplesModified = new ArrayList<Sample>();
    playbackFrame = 0;
  }
  void addSample( int x, int y ) {  // add sample when bRecording
    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" );
    if(samples.size() > 0){
      int deltax = samples.get(0).x - samples.get(samples.size()-1).x;
      int deltay = samples.get(0).y - samples.get(samples.size()-1).y;
      float sumdist = 0;
      
      for(int i = 0; i < samples.size() - 1; i++) {
        sumdist += sqrt((samples.get(i).x - samples.get(i +1 ).x)*(samples.get(i).x - samples.get(i +1 ).x) + (samples.get(i).y - samples.get(i +1 ).y)*(samples.get(i).y - samples.get(i +1 ).y));
      }
      
      samplesModified.add( new Sample(samples.get(0).t, samples.get(0).x , samples.get(0).y ) );
      float dist = 0;
      for(int i = 0; i < samples.size() - 1; i++) {
        dist += sqrt((samples.get(i).x - samples.get(i +1 ).x)*(samples.get(i).x - samples.get(i +1 ).x) + (samples.get(i).y - samples.get(i +1 ).y)*(samples.get(i).y - samples.get(i +1 ).y));
        samplesModified.add( new Sample(samples.get(i+1).t, (int) (samples.get(i +1).x + (dist * deltax) / sumdist), (int) (samples.get(i+1).y +( dist * deltay )/ sumdist)) );
        print(samples.get(i).x);
        print(",");
        print(samples.get(i).y);
        print(",");
        print( " good data x " + samplesModified.get(i).x);
        print(",");
        print( " good data y " + samplesModified.get(i).y);
        println("");      
      }
    }
  }
 
 
  void draw() {
    stroke( 255 );
    
    //**RECORD
    beginShape(LINES);
    for( int i=1; i<samples.size(); i++) {
      vertex( samplesModified.get(i-1).x, samplesModified.get(i-1).y ); // replace vertex with Pvector
      vertex( samplesModified.get(i).x, samplesModified.get(i).y );
    }
    endShape();
    //**ENDRECORD
    
    //**REPEAT
    int now = (millis() - startTime) % fullTime();
    if( now < samplesModified.get( playbackFrame ).t ) playbackFrame = 0;
    while( samplesModified.get( playbackFrame+1).t < now )
      playbackFrame = (playbackFrame+1) % (samples.size()-1);
    Sample s0 = samplesModified.get( playbackFrame );
    Sample s1 = samplesModified.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 );
      println( " good data y " + y);
    movementInterpolated=map (y, 0, 400, 0, TWO_PI);
  }
 } 

Sampler sampler;

void setup() {  
  size( 800, 800, P3D );
  frameRate( 30 );  
  sampler = new Sampler();
}

void draw() {
  background( 0 );
  activeSampling();
  stopSampling();
  
  if( actualSec!=lastSec){
       lastSec=actualSec;
       measure++;
       textSize (100);
       text (measure, 100, 100 );
     }
       actualSec =(int) (millis()*0.001);  // 
 
  if( bRecording) { // draw circle
    circle( mouseX, mouseY, 10 );
    sampler.addSample( mouseX, mouseY );
  }
  
  else {    
  if( sampler.fullTime() > 0 )
        sampler.draw();
  }
   
  drawBall( 1, movementInterpolated);
}

void mousePressed() {
  bRecording = true;   // draw circle
  mouseRecorded = true;
  measure=0;
}
  
void activeSampling() { 
   if (measure<=1 && measure>=1 &&actualSec!=lastSec && mouseRecorded == true) {
  sampler.beginRecording();
  }
}

void stopSampling() { 
   if (measure<=3 && measure>=3  && actualSec!=lastSec) {  
  mouseRecorded = false;
     //**REPEAT
  bRecording = false;
  sampler.beginPlaying();
  }
}

 void drawBall(int n, float phase) 
  { 
        pushMatrix();
        translate(-400, -400, -2000);
        noStroke();
        float side = height*0.15*1/this.nbBalls;
        float rayon = width/2; 
        float x = rayon*cos(phase);
        float y = rayon*sin(phase);
        translate (x, y, 200+(50*5*n));  
        colorMode(RGB, 255, 255, 255);
        fill( 0, 255, 0 ); 
        sphere(side*3);
        popMatrix();
    }

1 Like

Okay, the line I’ve drawn is shown in white.

A green ball follows the line.

But why is the big green ball still there in this case?

I don’t think this is true. He’s recording throughout - or what do you mean?

not sure, but measure can’t be < 1 AND > 1 at the same time. Hence you mean measure==1?


movementInterpolated

not clear. Maybe you can communicate what your final goal is?

You are referring to
movementInterpolated=map (y, 0, 400, 0, TWO_PI);

(it’s TWO_PI, not TWO)
(always nice when you tell us the code line you are referring to )

here is what you can do with movementInterpolated:

    // see y as 0 to TWO_PI
    movementInterpolated=map (y,
      0, 400,
      0, TWO_PI);
    // show 2 circles at right screen border
    circle( width-11, movementInterpolated+55, 12); // minimal movement
    circle( width-11, movementInterpolated*100+255, 12);  // movement enhanced by *100

    // calc circle pos x1,y1 with movementInterpolated as an angle
    float x1=cos(movementInterpolated) * 100 + (width-120);
    float y1=sin(movementInterpolated) * 100 + (255);
    fill(0, 0, 255);
    circle(x1, y1, 9);   // show point on circle with movementInterpolated as angle
    circle((width-120), 255, 9); // show center of circle

Remark

By the way in processing the order is (mostly (it’s only by convention))

  • global vars and objects
  • setup and draw
  • other functions
  • classes

It is unwise to name a method in a class draw(), just use display() instead


Full Sketch


int actualSec, lastSec, measure, measureToStartRecording;
boolean bRecording = false;
boolean mouseRecorded =  true;

int nbBalls=1;

float movementInterpolated;

Sampler sampler;

// ------------------------------------------------------------------------------------------------------
// Two core functions

void setup() {
  size( 800, 800, P3D );

  frameRate( 30 );
  sampler = new Sampler();
}//setup()

void draw() {
  background( 0 );
  activeSampling();
  stopSampling();

  if (actualSec!=lastSec) {
    lastSec=actualSec;
    measure++;
  }
  textSize(100);
  text(measure, 100, 100 );

  actualSec = (int) (millis()*0.001);  //

  if (bRecording) {
    // draw circle
    circle(mouseX, mouseY, 10 );
    sampler.addSample( mouseX, mouseY );
  } else {
    if (sampler.fullTime() > 0 )
      sampler.display();
  }

  drawBall(1, movementInterpolated);
}//draw()

// ------------------------------------------------------------------------------------------------------
// Inputs

void mousePressed() {
  bRecording = true;   // draw circle
  mouseRecorded = true;
  measure=0;
}

// ------------------------------------------------------------------------------------------------------
// other functions

void activeSampling() {
  if (measure<=1 && measure>=1 &&actualSec!=lastSec && mouseRecorded == true) {
    sampler.beginRecording();
    println ("here 18");
  }
}

void stopSampling() {
  if (measure<=3 && measure>=3  && actualSec!=lastSec) {
    mouseRecorded = false;
    //**REPEAT
    bRecording = false;
    sampler.beginPlaying();
  }
}

void drawBall(int n, float phase) {
  pushMatrix();
  translate(-400, -400, -2000);
  noStroke();
  float side = height*0.15*1/this.nbBalls;
  float rayon = width/2;
  float x = rayon*cos(phase);
  float y = rayon*sin(phase);
  translate (x, y, 200+(50*5*n));
  colorMode(RGB, 255, 255, 255);
  fill( 0, 255, 0 );
  sphere(side*3);
  popMatrix();
}

// ====================================================================
// Two classes

class Sample {
  int t, x, y;

  //constr
  Sample( int t, int x, int y ) {
    this.t = t;
    this.x = x;
    this.y = y;
  }//constr
  //
}//class

// ----

class Sampler {

  ArrayList<Sample> samples;
  ArrayList<Sample> samplesModified;

  int startTime;
  int playbackFrame;

  //constr
  Sampler() {
    samples = new ArrayList<Sample>();
    samplesModified = new ArrayList<Sample>();
    startTime = 0;
  }//constr

  void beginRecording() {
    samples = new ArrayList<Sample>();
    samplesModified = new ArrayList<Sample>();
    playbackFrame = 0;
  }

  void addSample( int x, int y ) {  // add sample when bRecording
    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() {
    // called only once
    println("here 12");
    startTime = millis();
    playbackFrame = 0;
    println( samples.size(), "samples over", fullTime(), "milliseconds" );
    if (samples.size() > 0) {
      int deltax = samples.get(0).x - samples.get(samples.size()-1).x;
      int deltay = samples.get(0).y - samples.get(samples.size()-1).y;
      float sumdist = 0;

      for (int i = 0; i < samples.size() - 1; i++) {
        sumdist += sqrt((samples.get(i).x - samples.get(i +1 ).x)*(samples.get(i).x - samples.get(i +1 ).x) + (samples.get(i).y - samples.get(i +1 ).y)*(samples.get(i).y - samples.get(i +1 ).y));
      }

      samplesModified.add( new Sample(samples.get(0).t, samples.get(0).x, samples.get(0).y ) );
      float dist = 0;
      for (int i = 0; i < samples.size() - 1; i++) {
        dist += sqrt((samples.get(i).x - samples.get(i +1 ).x)*(samples.get(i).x - samples.get(i +1 ).x) + (samples.get(i).y - samples.get(i +1 ).y)*(samples.get(i).y - samples.get(i +1 ).y));
        samplesModified.add( new Sample(samples.get(i+1).t, (int) (samples.get(i +1).x + (dist * deltax) / sumdist), (int) (samples.get(i+1).y +( dist * deltay )/ sumdist)) );
        print(samples.get(i).x);
        print(",");
        print(samples.get(i).y);
        print(",");
        print( " good data x " + samplesModified.get(i).x);
        print(",");
        print( " good data y " + samplesModified.get(i).y);
        println("");
      }
    }
  }

  void display() {
    stroke( 255 );

    //**RECORD
    beginShape(LINES);
    for ( int i=1; i<samples.size(); i++) {
      vertex( samplesModified.get(i-1).x, samplesModified.get(i-1).y ); // replace vertex with Pvector
      vertex( samplesModified.get(i).x, samplesModified.get(i).y );
    }
    endShape();
    //**ENDRECORD

    //**REPEAT
    int now = (millis() - startTime) % fullTime();
    if ( now < samplesModified.get( playbackFrame ).t ) playbackFrame = 0;
    while ( samplesModified.get( playbackFrame+1).t < now )
      playbackFrame = (playbackFrame+1) % (samples.size()-1);
    Sample s0 = samplesModified.get( playbackFrame );
    Sample s1 = samplesModified.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 );
    println( " good data y " + y);

    // see y as 0 to TWO_PI
    movementInterpolated=map (y,
      0, 400,
      0, TWO_PI);
    // show 2 circles at right screen border
    circle( width-11, movementInterpolated+55, 12); // minimal movement
    circle( width-11, movementInterpolated*100+255, 12);  // movement enhanced by *100

    // calc circle pos x1,y1 with movementInterpolated as an angle
    float x1=cos(movementInterpolated) * 100 + (width-120);
    float y1=sin(movementInterpolated) * 100 + (255);
    fill(0, 0, 255);
    circle(x1, y1, 9);   // show point on circle with movementInterpolated as angle
    circle((width-120), 255, 9); // show center of circle

    //
  }//method
  //
}//class
//

2 Likes

Hi Mister,
Thank for helping me :wink:

I wanted to say, I want to follow the movement drawn in white color doing a loop.
If you try to record a big circle with the mouse you will see that your circle an my green ball turn in the same way. But sometimes, depending of the movement drawn in white color we have some jumps, glitches in the movement made by your circle and my ball.
I think it is possible to fix this bug by mapping the interpolatedmovement with better method.
I wrote at line 206 a possible method.
I will explain my final goal a bit later.

Thank you so much


int actualSec, lastSec, measure, measureToStartRecording;
boolean bRecording = false;
boolean mouseRecorded =  true;
int nbBalls=1;

float movementInterpolated;
float formerInterpolatedY,interpolatedY;

Sampler sampler;

// ------------------------------------------------------------------------------------------------------
// Two core functions

void setup() {
  size( 800, 800, P3D );

  frameRate( 30 );
  sampler = new Sampler();
}//setup()

void draw() {
  background( 0 );
  activeSampling();
  stopSampling();

  if (actualSec!=lastSec) {
    lastSec=actualSec;
    measure++;
  }
  textSize(100);
  text(measure, 100, 100 );

  actualSec = (int) (millis()*0.001);  //

  if (bRecording) {
    // draw circle
    circle(mouseX, mouseY, 10 );
    sampler.addSample( mouseX, mouseY );
  } else {
    if (sampler.fullTime() > 0 )
      sampler.display();
  }

  drawBall(1, movementInterpolated);
}//draw()

// ------------------------------------------------------------------------------------------------------
// Inputs

void mousePressed() {
  bRecording = true;   // draw circle
  mouseRecorded = true;
  measure=0;
}

// ------------------------------------------------------------------------------------------------------
// other functions

void activeSampling() {
  if (measure==1 && actualSec!=lastSec && mouseRecorded == true) {
    sampler.beginRecording();
    println ("here 18");
  }
}

void stopSampling() {
  if (measure==3  && actualSec!=lastSec) {
    mouseRecorded = false;
    //**REPEAT
    bRecording = false;
    sampler.beginPlaying();
  }
}

void drawBall(int n, float phase) {
  pushMatrix();
  translate(-400, -400, -2000);
  noStroke();
  float side = height*0.15*1/this.nbBalls;
  float rayon = width/2;
  float x = rayon*cos(phase);
  float y = rayon*sin(phase);
  translate (x, y, 200+(50*5*n));
  colorMode(RGB, 255, 255, 255);
  fill( 0, 255, 0 );
  sphere(side*3);
  popMatrix();
}

// ====================================================================
// Two classes

class Sample {
  int t, x, y;

  //constr
  Sample( int t, int x, int y ) {
    this.t = t;
    this.x = x;
    this.y = y;
  }//constr
  //
}//class

// ----

class Sampler {

  ArrayList<Sample> samples;
  ArrayList<Sample> samplesModified;

  int startTime;
  int playbackFrame;

  //constr
  Sampler() {
    samples = new ArrayList<Sample>();
    samplesModified = new ArrayList<Sample>();
    startTime = 0;
  }//constr

  void beginRecording() {
    samples = new ArrayList<Sample>();
    samplesModified = new ArrayList<Sample>();
    playbackFrame = 0;
  }

  void addSample( int x, int y ) {  // add sample when bRecording
    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() {
    // called only once
    println("here 12");
    startTime = millis();
    playbackFrame = 0;
    println( samples.size(), "samples over", fullTime(), "milliseconds" );
    if (samples.size() > 0) {
      int deltax = samples.get(0).x - samples.get(samples.size()-1).x;
      int deltay = samples.get(0).y - samples.get(samples.size()-1).y;
      float sumdist = 0;

      for (int i = 0; i < samples.size() - 1; i++) {
        sumdist += sqrt((samples.get(i).x - samples.get(i +1 ).x)*(samples.get(i).x - samples.get(i +1 ).x) + (samples.get(i).y - samples.get(i +1 ).y)*(samples.get(i).y - samples.get(i +1 ).y));
      }

      samplesModified.add( new Sample(samples.get(0).t, samples.get(0).x, samples.get(0).y ) );
      float dist = 0;
      for (int i = 0; i < samples.size() - 1; i++) {
        dist += sqrt((samples.get(i).x - samples.get(i +1 ).x)*(samples.get(i).x - samples.get(i +1 ).x) + (samples.get(i).y - samples.get(i +1 ).y)*(samples.get(i).y - samples.get(i +1 ).y));
        samplesModified.add( new Sample(samples.get(i+1).t, (int) (samples.get(i +1).x + (dist * deltax) / sumdist), (int) (samples.get(i+1).y +( dist * deltay )/ sumdist)) );
        print(samples.get(i).x);
        print(",");
        print(samples.get(i).y);
        print(",");
        print( " good data x " + samplesModified.get(i).x);
        print(",");
        print( " good data y " + samplesModified.get(i).y);
        println("");
      }
    }
  }

  void display() {
    stroke( 255 );

    //**RECORD
    beginShape(LINES);
    for ( int i=1; i<samples.size(); i++) {
      vertex( samplesModified.get(i-1).x, samplesModified.get(i-1).y ); // replace vertex with Pvector
      vertex( samplesModified.get(i).x, samplesModified.get(i).y );
    }
    endShape();
    //**ENDRECORD

    //**REPEAT
    int now = (millis() - startTime) % fullTime();
    if ( now < samplesModified.get( playbackFrame ).t ) playbackFrame = 0;
    while ( samplesModified.get( playbackFrame+1).t < now )
      playbackFrame = (playbackFrame+1) % (samples.size()-1);
    Sample s0 = samplesModified.get( playbackFrame );
    Sample s1 = samplesModified.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 );
    println( " good data y " + y);
    
    //my modification
     formerInterpolatedY=interpolatedY;
     interpolatedY= constrain ( lerp( s0.y, s1.y, dt ), 0, 800);
     
     // a possible to have movement in the same way
       if (formerInterpolatedY<=interpolatedY){
       movementInterpolated= map (interpolatedY, 800, 0, 0, TWO_PI);  // map from the highest interpolated point to lowest interpolated point
       }
       else
       {
       movementInterpolated=map (interpolatedY, 0, 800, 0, TWO_PI);  // map from the lowest interpolated point to highest interpolated point
      }
    
    
    // former modification
   
    // see y as 0 to TWO_PI
    // movementInterpolated=map (y,
    //  0, 400,
    //  0, TWO_PI);   
      
    // show VerticalMovement 2 circles at right screen border
    circle( width-11, movementInterpolated+55, 12); // minimal movement
    circle( width-11, movementInterpolated*100+255, 12);  // movement enhanced by *100

    // calc circle pos x1,y1 with movementInterpolated as an angle
    float x1=cos(movementInterpolated) * 100 + (width-120);
    float y1=sin(movementInterpolated) * 100 + (255);
    fill(0, 0, 255);
    circle(x1, y1, 9);   // show point on circle with movementInterpolated as angle
    circle((width-120), 255, 9); // show center of circle

    //
  }//method
  //
}//class
//
1 Like

Hello super Mister.

I changed the program.
Now, i have perfect angle to interpolate, not a shape drawn with the mouse.

I think you will have solution, quite easy.
I will try make a video tomorow in order to see what i’m trying to do.

Take care of you.
Benjamin

1 Like

Hello!

you can also just record a circle based on the angle between mouse and screen center (core idea is using atan2() here).

This circle would have a fixed radius.

Remark

When you have a real circle and know its center and radius, you can of course calc the intermediate points (not only one but all):

  • calc the angle from last point a1
  • calc the angle from first point a2
  • for loop a_intermediate from a1 to a2; lots of ways to do this;
    for(int a_intermediate = degree(a1); a_intermediate <= degree(a2); a_intermediate++) {
    or use lerp() between the angles a1 and a2 (not between the points obviously).
  • calc x and y based on a_intermediate and cos and sin (and r and center) like here:
float x=cos(a_intermediate) * r + centerX; 
float y=sin(a_intermediate) * r + centerY;

Warm regards,

Chrisir


Full Sketch

(without the remark above)



void setup() {
  size(800, 600);
}

void draw() {
  background(204);

  float a = calcAngle();

  //----------------------------------------

  pushMatrix();
  translate(width/2, height/2);
  rotate(a);
  translate(28, 0);
  rect(-30, -5, 60, 10);
  popMatrix();

  //----------------------------------------

  ellipse(width/2, height/2, 5, 5);
  text(degrees(a), 22, 22);
}

//----------------------------------------------------------------------

float calcAngle() {

  // calc angle between mouse and screen center

  float a = atan2(mouseY-height/2, mouseX-width/2);

  if (a<0) {
    a=map(a, -PI, 0,
      PI, TWO_PI);
  }

  return a;
}
//

new version where the points on the circle are shown separately using :

  stroke(255, 0, 0);
  ellipse(
    cos(a) * 150 + width/2.0,
    sin(a) * 150 + height/2.0,
    4,
    4
    );

Full Sketch



void setup() {
  size(800, 600);
}

void draw() {
  // background(204);

  float a = calcAngle();

  //----------------------------------------

  pushMatrix();
  translate(width/2, height/2);
  rotate(a);
  translate(28, 0);
  stroke(0);
  rect(-30, -5, 60, 10);
  popMatrix();

  //----------------------------------------

  stroke(255, 0, 0);
  ellipse(
    cos(a) * 150 + width/2.0,
    sin(a) * 150 + height/2.0,
    4,
    4
    );

  stroke(0);
  ellipse(width/2, height/2, 5, 5);
  text(degrees(a), 22, 22);
}

//----------------------------------------------------------------------

float calcAngle() {

  // calc angle between mouse and screen center

  float a = atan2(mouseY-height/2, mouseX-width/2);

  if (a<0) {
    a=map(a, -PI, 0,
      PI, TWO_PI);
  }

  return a;
}
//

1 Like

Hi,

I changed the program with yours remarks.
It 's totatlly better to record position of the ball like that. :slightly_smiling_face:
As you said :

That’s i’m tring to do but i do not retreive the first and the last datas sampled :cold_face:

Here my changes

int actualSec;
int lastSec;

int virtualV2;

float mlerp(float x0, float x1, float t, float M ){
   float dx = (x1 - x0 + 1.5*M) % M - 0.5*M;
   return (x0 + t * dx + M) % M;
}
float interpolatedAngle;
float angleToInterpolate;

boolean bRecording = false;
boolean mouseRecorded;
float currTime;
float nextSamplePeriod = 2.0;
int measure;

class Sample {
  float t, y;
  Sample( float t, float y ) {
    this.t = t;  this.y = y;
  }
}
class Sampler {
  ArrayList<Sample> samples;
  float startTime;
  float sampleLengthTime;
  float period;
  int playbackFrame;
  
 //**** SCULDY COMPUTATION TO PUT HERE ??

  Sampler( float newPeriod, float now,  float y ) {
    samples = new ArrayList<Sample>();
    startTime = now;
    addSample( now, y );
    playbackFrame = 0;
    period = newPeriod;
  }
  void addSample( float now, float y ) {
    samples.add( new Sample( now - startTime, y ) );
    sampleLengthTime = now - startTime;
    if( sampleLengthTime > period )
      bRecording = false;
      mouseRecorded = false;
    // round up the period to the next power of 2
    //period = sampleLengthTime < 1 ? 1 :
    //  pow( 2, max( 0, ceil( log( sampleLengthTime ) / log(2) ) ) );
  }
  void drawRecordingWithVertexes( float now ){
    if( samples.size() < 2 ) return;
    
    // draw the sample trail
    stroke( 200 );
    beginShape(LINES);
    for( int i=1; i<samples.size(); i++) {
      vertex( samples.get(i-1).y, samples.get(i).y );  // replace vertex with Pvector ???
  
    }
    endShape();

    // draw the current sample point
    //float st = (now - startTime) % period;
    float st = now % period;
    if( st > sampleLengthTime ) return;
    if( st < samples.get( playbackFrame ).t ) playbackFrame = 0;
    while( samples.get( playbackFrame+1).t < st )
      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 = (st - t0) / (t1 - t0);
 
 // float x = mlerp( s0.x, s1.x, dt, 400 ); // interpolation with 'continious datas'
    float y = mlerp( s0.y, s1.y, dt, TWO_PI ); // interpolation with 'radian datas'
    
    interpolatedAngle = y;  // angle between themselves not from the first and the last!
    
    for( int i=1; i<samples.size(); i++) {
      
    print ( " interpolatedAngle "  + interpolatedAngle + " first angle " + samples.get(0) +  " last angle "  +  samples.get(samples.size()-1)); 
     }
      
    noStroke();
    fill( 255, 40, 40 );
    circle ( 100* cos ( interpolatedAngle)+400, 100*sin ( interpolatedAngle)+200, 20);
  }
}

Sampler sampler;
ArrayList<Sampler> samplers;

void setup() {
  size( 800, 800, P3D );
  frameRate( 30 );
  samplers = new ArrayList<Sampler>();
}

void draw() {
   println ( " measure " + measure );
     if  (actualSec<lastSec){         
         measure=measure+1;        
     }
         lastSec=actualSec; 
         actualSec = millis()%1000;  // Values from 0 - 2
  
  activeSamplingSecond();
  samplingMovementPro();  

  angleToInterpolate = calcAngle();
 
  
  fill( 100, 0, 0);
  circle ( 100* cos (angleToInterpolate)+200, 100*sin (angleToInterpolate)+200, 20);
   
  //----------------------------------------

  pushMatrix();
  translate(width/2, height/2);
  rotate(angleToInterpolate);
  translate(28, 0);
  rect(-30, -5, 60, 10);
  popMatrix();

  //----------------------------------------
  ellipse(width/2, height/2, 5, 5);
  text(degrees(angleToInterpolate), 22, 22);
  
  }
  
  //----------------------------------------------------------------------

float calcAngle() {


  float a = atan2(mouseY-height/2, mouseX-width/2);

  if (a<0) {
    a=map(a, -PI, 0,
      PI, TWO_PI);
  }
  return a;
}
    
 
void samplingMovementPro() {
  
  currTime = millis() * 0.001;  // seconds since app started
  background( 0 );
  for( int i=0; i<3; i++ ) {
    float p = pow( 2, i );
    stroke( 64, p == nextSamplePeriod ? 255 : 64, 64 );
    rect( (currTime % p) / p * width, i*10, 2, 8 );
  }

  if( bRecording ) {
      samplers.get(samplers.size()-1).addSample( currTime, angleToInterpolate ); // 
  }
  
  for( Sampler s : samplers )
    s.drawRecordingWithVertexes( currTime );
}

void mousePressed() {  
   mouseRecorded = true;
   measure=0;
   }


void activeSamplingSecond() { 
   if (measure==0 && actualSec!=lastSec && mouseRecorded == true) {
  bRecording = true;
  samplers.add( new Sampler( nextSamplePeriod, currTime, angleToInterpolate ) );// work almost with mouseY=v1 
  }
}

void keyPressed() {
  if( key == '1' )
    nextSamplePeriod = 1.0;
  else if( key == '2' )
    nextSamplePeriod = 2.0;
  else if( key == '4' )
    nextSamplePeriod = 4.0;
  else if( key == '8' )
    nextSamplePeriod = 8.0;
  else if( key == 'X' ) {
  if( samplers.size() > 0 )
      samplers.remove( samplers.size() - 1 );
  }
}

lerp() is an in-built function, see reference

Did you use it?

yes.
Here for 40 point between the first and last point.
for (int i = 0; i <= 40; i++) {
float x = lerp(x1, x2, i/40.0) + 40;
// float y = lerp(y1, y2, i/40.0);
point(x, 100);
}
But my little question is just how can i retreive the fist and the last data of my sample i tried this

for( int i=1; i<samples.size(); i++) {      
    print ( " interpolatedAngle "  + interpolatedAngle + " first angle " + samples.get(0) +  " last angle "  +  samples.get(samples.size()-1)); 
     }

but i read this

interpolatedAngle 3.626964 first angle scudly_sample_chisir_Tangente$Sample@654c74e9 last angle scudly_sample_chisir_Tangente$Sample@5638b99

Ok.
I retreive first and last data like that.

    print ( " interpolatedAngle "  + interpolatedAngle + " first angle " + samples.get(0).y +  " last angle "  +  samples.get(samples.size()-1).y); 

I’m going tot try to interpolate.