Dear everyones
The idea is to record any movement for 2 sec, transform it to loop it (so that the movement is ‘full’) and play it back for exactly 2 sec. To replay the transformed movement, the movement must be distorted so that it loops exactly for 2 sec.
The first program below registers a movement and completes it by creating a bezier curve between the first and the last point.
You press one the mouse, and the program will record a shape for 2 sec.
The second records a movement and plays it back but it does not fill the loop.
I have to combine these two programs, but I have no idea how to do it. should not be too complicated for the people managing the classes
I really need this option, I don’t know how to thank you.
Benjamin
int actualSec,lastSec,measure,measureToStartRecording;
boolean preActivateRecording = false;
boolean endRecording = false;
boolean mouseRecorded = false;
final Path path = new Path();
void setup() {
size( 800, 800, P3D );
frameRate( 30 );
}
void draw() {
background(0);
drawShape();
if (actualSec!=lastSec){
lastSec=actualSec;
measure++;
}
actualSec =(int) (millis()*0.001); //
if (measure>=measureToStartRecording+2 && actualSec!=lastSec && endRecording == true ) {
preActivateRecording = false;
mouseRecorded = false;
endSampling();
endRecording = false;
}
println ( " preActivateRecording ", preActivateRecording, " measure", measure, " measureToStartRecording", measureToStartRecording);
path.draw();
}
void drawShape() {
path.mouseDragged();
}
void mousePressed() {
mouseRecorded =true;
path.startNewSample();
}
void endSampling() {
path.endSampling();
}
import java.util.function.Predicate;
final class Automater {
private static final int STEPS = 60;
private final ArrayList<PVector> anchors;
private final Anchor head;
private final Anchor tail;
Automater(ArrayList<PVector> anchors) {
this.anchors = new ArrayList<>(anchors);
head = new Anchor(true);
tail = new Anchor(false);
}
ArrayList<PVector> build() {
final ArrayList<PVector> xys = new ArrayList<>();
final float x1 = head.loc.x;
final float y1 = head.loc.y;
final float x2 = tail.loc.x;
final float y2 = tail.loc.y;
for (int i = 0; i < STEPS; i++) {
final float t = i / (float) STEPS;
final float x = bezierPoint(
x1, x1 + head.vel.x,
x2 + tail.vel.x, x2, t);
final float y = bezierPoint(
y1, y1 + head.vel.y,
y2 + tail.vel.y, y2, t);
xys.add(new PVector(x, y));
}
return xys;
}
private final class Anchor {
private final PVector loc;
private final PVector vel;
Anchor(boolean head) {
final int id = (head) ? anchors.size() - 1 : 0;
loc = anchors.get(id);
vel = initVel(head, id).mult((head) ? 1 : -1);
}
private PVector initVel(boolean head, int id) {
final Direction xDir = new Direction();
final Direction yDir = new Direction();
for (int i = 1; i < (anchors.size() / 2); i++) {
final int curr = (head) ? id - i : i;
final PVector currLoc = anchors.get(curr);
final PVector prevLoc = anchors.get(curr - 1);
xDir.update(currLoc.x, prevLoc.x);
yDir.update(currLoc.y, prevLoc.y);
if (xDir.done || yDir.done) {
break;
}
}
return new PVector(xDir.total, yDir.total);
}
private class Direction {
Predicate<Float> test;
boolean done;
boolean lock;
float total;
private void update(float xyCurr, float xyPrev) {
final Float vel = xyCurr - xyPrev;
if (!lock && vel != 0) {
lock = true;
test = (vel > 0) ? e -> e >= 0 : e -> e <= 0;
}
if (lock) {
if (!test.test(vel)) {
done = true;
return;
}
}
total += vel;
}
}
}
}
final class Path {
private static final int ANCHOR_SIZE = 8;
private final ArrayList<PVector> autoAnchors = new ArrayList<>();
private final ArrayList<PVector> userAnchors = new ArrayList<>();
void draw() {
pushStyle();
ellipseMode(CENTER);
stroke(0);
strokeWeight(1);
drawAnchors(userAnchors, #FFFFFF);
drawAnchors(autoAnchors, #FF8C00);
popStyle();
}
private void drawAnchors(ArrayList<PVector> anchors, color c) {
fill(c);
anchors.stream().forEach(e -> ellipse(e.x, e.y, ANCHOR_SIZE, ANCHOR_SIZE));
}
void mouseDragged() {
if ( preActivateRecording){ //draw vector
userAnchors.add(new PVector(mouseX, mouseY));
}
}
void startNewSample() {
measureToStartRecording=measure;
preActivateRecording=true;
autoAnchors.clear();
userAnchors.clear();
endRecording = true;
}
void endSampling() {
final Automater automater = new Automater(userAnchors);
ArrayList<PVector> anchors = automater.build();
anchors.stream().forEach(e -> autoAnchors.add(new PVector(e.x, e.y)));
}
}
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();
}
}