add timeline
This commit is contained in:
parent
6a755d42cc
commit
bd01ea3f78
|
@ -0,0 +1,168 @@
|
||||||
|
|
||||||
|
public class Timeline
|
||||||
|
{
|
||||||
|
PVector posOrigin;
|
||||||
|
PVector size;
|
||||||
|
|
||||||
|
int textsize=12;
|
||||||
|
|
||||||
|
color cborder = color(200,200,200);
|
||||||
|
color ctimeslider = color(255,255,255);
|
||||||
|
|
||||||
|
private float time_start; //in seconds
|
||||||
|
private float time_end;
|
||||||
|
|
||||||
|
float[] preview_cmd;
|
||||||
|
float[] preview_throttle;
|
||||||
|
float[] preview_brake;
|
||||||
|
float[] preview_currentAll;
|
||||||
|
|
||||||
|
public Timeline(int px, int py, int pw, int ph) {
|
||||||
|
this.posOrigin= new PVector(px,py); //lower left corner
|
||||||
|
this.size = new PVector(pw,ph); //to the right and up
|
||||||
|
|
||||||
|
preview_cmd=new float[(int)this.size.x];
|
||||||
|
preview_throttle=new float[(int)this.size.x];
|
||||||
|
preview_brake=new float[(int)this.size.x];
|
||||||
|
preview_currentAll=new float[(int)this.size.x];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void generatePreview(Table logdata) {
|
||||||
|
int cID=0; //current ID for generating preview in datalog
|
||||||
|
for (int x=0;x<this.size.x;x++) //for every width pixel of timeline
|
||||||
|
{
|
||||||
|
float t1=xPosToTimeSeconds(x); //time start for this pixel
|
||||||
|
float t2=xPosToTimeSeconds(x+1); //time end for this pixel
|
||||||
|
while ((cID+1 < logdata.getRowCount()) && ( t1 > (logdata.getRow(cID+1).getFloat("time")))) { //while starttime not reached
|
||||||
|
cID++; //next
|
||||||
|
}
|
||||||
|
int preview_mean_counter=0;
|
||||||
|
float preview_mean_cmd=0;
|
||||||
|
float preview_mean_brake=0;
|
||||||
|
float preview_mean_throttle=0;
|
||||||
|
float preview_mean_currentAll=0;
|
||||||
|
|
||||||
|
|
||||||
|
while ((cID+1 < logdata.getRowCount()) && ( t2 > (logdata.getRow(cID+1).getFloat("time")))) { //while endtime not reached
|
||||||
|
TableRow row = logdata.getRow(cID);
|
||||||
|
nextTimeData=(long)(logdata.getRow(cID+1).getFloat("time")*1000); //get time and convert from seconds to ms
|
||||||
|
|
||||||
|
lastTimeMillis=nextTimeMillis;
|
||||||
|
|
||||||
|
|
||||||
|
preview_mean_cmd += (row.getInt("cmd_FrontL")+row.getInt("cmd_FrontR")+row.getInt("cmd_RearL")+row.getInt("cmd_RearR"))/4.0;
|
||||||
|
preview_mean_brake += row.getInt("brake");
|
||||||
|
preview_mean_throttle += row.getInt("throttle");
|
||||||
|
preview_mean_currentAll += row.getFloat("currentAll");
|
||||||
|
/*
|
||||||
|
current_FrontL=row.getFloat("current_FrontL");
|
||||||
|
current_FrontR=row.getFloat("current_FrontR");
|
||||||
|
current_RearL=row.getFloat("current_RearL");
|
||||||
|
current_RearR=row.getFloat("current_RearR");
|
||||||
|
speed_FrontL=row.getInt("speed_FrontL");
|
||||||
|
speed_FrontR=row.getInt("speed_FrontR");
|
||||||
|
speed_RearL=row.getInt("speed_RearL");
|
||||||
|
speed_RearR=row.getInt("speed_RearR");
|
||||||
|
temp_Front=row.getFloat("temp_Front");
|
||||||
|
temp_Rear=row.getFloat("temp_Rear");
|
||||||
|
vbat_Front=row.getFloat("vbat_Front");
|
||||||
|
vbat_Rear=row.getFloat("vbat_Rear");
|
||||||
|
currentAll=row.getFloat("currentAll");
|
||||||
|
throttle=row.getInt("throttle");
|
||||||
|
brake=row.getInt("brake");*/
|
||||||
|
|
||||||
|
preview_mean_counter++;
|
||||||
|
|
||||||
|
cID++; //next
|
||||||
|
}
|
||||||
|
preview_mean_cmd/=preview_mean_counter;
|
||||||
|
preview_mean_brake/=preview_mean_counter;
|
||||||
|
preview_mean_throttle/=preview_mean_counter;
|
||||||
|
preview_mean_currentAll/=preview_mean_counter;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
preview_cmd[x]=preview_mean_cmd;
|
||||||
|
preview_brake[x]=preview_mean_brake;
|
||||||
|
preview_throttle[x]=preview_mean_throttle;
|
||||||
|
preview_currentAll[x]=preview_mean_currentAll;
|
||||||
|
}//next pixel
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimes(float _start,float _end) {
|
||||||
|
this.time_start=_start;
|
||||||
|
this.time_end=_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void drawTL(float _time) {
|
||||||
|
//Preview visualization
|
||||||
|
for (int x=0;x<this.size.x;x++) //for every width pixel of timeline
|
||||||
|
{
|
||||||
|
if (!Float.isNaN(preview_cmd[x])) {
|
||||||
|
float preview_cmd_scaled=constrain(map(preview_cmd[x],0,1000,0.0,1.0), 0.0,1.0);
|
||||||
|
preview_cmd_scaled=sqrt(sqrt(preview_cmd_scaled))+0.1;//more contrast
|
||||||
|
|
||||||
|
float preview_currentAll_scaled=constrain(map(preview_currentAll[x],0,10,0.0,1.0), 0.0,1.0);
|
||||||
|
preview_currentAll_scaled=sqrt(sqrt(preview_currentAll_scaled));//more contrast
|
||||||
|
|
||||||
|
colorMode(HSB, 360, 100, 100);
|
||||||
|
stroke(color(200-preview_currentAll_scaled*200,100,preview_cmd_scaled*100));
|
||||||
|
line(this.posOrigin.x+x,this.posOrigin.y,this.posOrigin.x+x,this.posOrigin.y+this.size.y); //color gradient background
|
||||||
|
|
||||||
|
float preview_throttle_scaled=constrain(map(preview_throttle[x],0,1000,0.0,1.0), 0.0,1.0);
|
||||||
|
colorMode(HSB, 360, 100, 100);
|
||||||
|
stroke(color(240,100,100));
|
||||||
|
line(this.posOrigin.x+x,this.posOrigin.y+this.size.y,this.posOrigin.x+x,this.posOrigin.y+this.size.y*(1-preview_throttle_scaled/2)); //line bottom up
|
||||||
|
|
||||||
|
float preview_brake_scaled=constrain(map(preview_brake[x],0,1000,0.0,1.0), 0.0,1.0);
|
||||||
|
colorMode(HSB, 360, 100, 100);
|
||||||
|
stroke(color(0,100,100));
|
||||||
|
line(this.posOrigin.x+x,this.posOrigin.y,this.posOrigin.x+x,this.posOrigin.y+this.size.y*preview_brake_scaled/2); //line top down
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Boarder
|
||||||
|
rectMode(CORNERS);
|
||||||
|
noFill();
|
||||||
|
stroke(this.cborder);
|
||||||
|
rect(this.posOrigin.x,this.posOrigin.y,this.posOrigin.x+this.size.x,this.posOrigin.y+this.size.y); //border
|
||||||
|
|
||||||
|
//current time
|
||||||
|
int timeslider_xpos = (int)( this.posOrigin.x+timeSecondsToXPos(_time) );
|
||||||
|
stroke(this.ctimeslider);
|
||||||
|
line(timeslider_xpos,this.posOrigin.y-3,timeslider_xpos,this.posOrigin.y+this.size.y+3);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
textSize(this.textsize);
|
||||||
|
textAlign(CENTER);
|
||||||
|
text(int(this.time_start+0.5)+"s", this.posOrigin.x, this.posOrigin.y-1); //starttime
|
||||||
|
text(int(this.time_end+0.5)+"s", this.posOrigin.x+this.size.x, this.posOrigin.y-1); //endtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public float checkMouse(int mx, int my)
|
||||||
|
{
|
||||||
|
if (mx>=this.posOrigin.x && mx <=this.posOrigin.x+this.size.x && my>=this.posOrigin.y && my<=this.posOrigin.y+this.size.y) { //mouse whithin timeline boarder
|
||||||
|
float mousetime=xPosToTimeSeconds((int)(mx-this.posOrigin.x));
|
||||||
|
//float mousetimesliderpercent=(mx-this.posOrigin.x)/this.size.x;
|
||||||
|
//float mousetime=mousetimesliderpercent*(this.time_end-this.time_start)+this.time_start;
|
||||||
|
return millis()/1000.0-mousetime;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int timeSecondsToXPos(float _time) {
|
||||||
|
float timesliderpercent = (_time-this.time_start)/(this.time_end-this.time_start); //0<= x <=1
|
||||||
|
return (int)(timesliderpercent*this.size.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float xPosToTimeSeconds(int _x) {
|
||||||
|
float mousetimesliderpercent=_x/this.size.x;
|
||||||
|
return mousetimesliderpercent*(this.time_end-this.time_start)+this.time_start;
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,8 @@ abstract class Visualization
|
||||||
boolean showMinMax=false;
|
boolean showMinMax=false;
|
||||||
|
|
||||||
//default colors (not all used by every implementation)
|
//default colors (not all used by every implementation)
|
||||||
|
|
||||||
|
|
||||||
color cmain = color(255,255,255);
|
color cmain = color(255,255,255);
|
||||||
color cmain2 = color(255,255,255);
|
color cmain2 = color(255,255,255);
|
||||||
color cscale = color(100,100,100);
|
color cscale = color(100,100,100);
|
||||||
|
|
|
@ -12,6 +12,10 @@ Serial serial;
|
||||||
String serialString=""; //last read string
|
String serialString=""; //last read string
|
||||||
int serial_endchar=10; //10=ASCII Linefeed
|
int serial_endchar=10; //10=ASCII Linefeed
|
||||||
|
|
||||||
|
//timeline
|
||||||
|
float logdata_start_time=0;
|
||||||
|
float logdata_end_time=0;
|
||||||
|
|
||||||
Visualization vis_cmd_FrontL;
|
Visualization vis_cmd_FrontL;
|
||||||
Visualization vis_cmd_FrontR;
|
Visualization vis_cmd_FrontR;
|
||||||
Visualization vis_cmd_RearL;
|
Visualization vis_cmd_RearL;
|
||||||
|
@ -41,8 +45,9 @@ Visualization vis_graph_speed_mean;
|
||||||
|
|
||||||
Visualization vis_c_graph_receivedelay;
|
Visualization vis_c_graph_receivedelay;
|
||||||
|
|
||||||
|
boolean showTimeline=!useSerial;
|
||||||
|
Timeline tl;
|
||||||
|
int timeoffset=0; //for moving timeslider
|
||||||
|
|
||||||
|
|
||||||
Table logdata;
|
Table logdata;
|
||||||
|
@ -52,6 +57,8 @@ long nextTimeData=0; //time of nextID row
|
||||||
long lastTimeMillis=0; //local time
|
long lastTimeMillis=0; //local time
|
||||||
long nextTimeMillis=0; //local time
|
long nextTimeMillis=0; //local time
|
||||||
|
|
||||||
|
boolean newdataforced=false;
|
||||||
|
|
||||||
int dataErrorCount=0;
|
int dataErrorCount=0;
|
||||||
|
|
||||||
//Data from log
|
//Data from log
|
||||||
|
@ -78,8 +85,8 @@ int brake;
|
||||||
color bg=color(0);
|
color bg=color(0);
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
size(1920, 1080);
|
//size(1920, 1080);
|
||||||
//size(1000, 800);
|
size(1000, 800);
|
||||||
frameRate(100);
|
frameRate(100);
|
||||||
|
|
||||||
if (useSerial) {
|
if (useSerial) {
|
||||||
|
@ -96,8 +103,9 @@ void setup() {
|
||||||
serialString = null;
|
serialString = null;
|
||||||
}else{
|
}else{
|
||||||
logdata = loadTable(logfile_name, "header, csv");
|
logdata = loadTable(logfile_name, "header, csv");
|
||||||
|
logdata_start_time=logdata.getRow(0).getFloat("time");
|
||||||
println("loaded "+logdata.getRowCount()+" lines. Times: "+logdata.getRow(0).getFloat("time")+"s to "+logdata.getRow(logdata.getRowCount()-1).getFloat("time")+"s");
|
logdata_end_time = logdata.getRow(logdata.getRowCount()-1).getFloat("time");
|
||||||
|
println("loaded "+logdata.getRowCount()+" lines. Times: "+logdata_start_time+"s to "+logdata_end_time+"s");
|
||||||
}
|
}
|
||||||
|
|
||||||
PVector pos_vis_cmd = new PVector(100,200);
|
PVector pos_vis_cmd = new PVector(100,200);
|
||||||
|
@ -211,11 +219,16 @@ void setup() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (showTimeline) {
|
||||||
|
tl = new Timeline(30,height-30, width-30*2, 28);
|
||||||
|
tl.setTimes(logdata_start_time,logdata_end_time);
|
||||||
|
tl.generatePreview(logdata);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw() {
|
void draw() {
|
||||||
long loopmillis=millis();
|
long loopmillis=millis()-timeoffset;
|
||||||
|
|
||||||
if (useSerial) {
|
if (useSerial) {
|
||||||
if (serial.available() > 0) {
|
if (serial.available() > 0) {
|
||||||
|
@ -257,8 +270,11 @@ void draw() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
while (loopmillis>=nextTimeData && nextID+1<logdata.getRowCount()){ //New Data
|
while (newdataforced || loopmillis>=nextTimeData && nextID+1<logdata.getRowCount()){ //New Data
|
||||||
|
newdataforced=false; //reset flag
|
||||||
|
if ((nextID+1 < logdata.getRowCount()) && (nextID-1 > 0)) { //valid row
|
||||||
TableRow row = logdata.getRow(nextID);
|
TableRow row = logdata.getRow(nextID);
|
||||||
|
|
||||||
lastTimeData=nextTimeData;
|
lastTimeData=nextTimeData;
|
||||||
nextTimeData=(long)(logdata.getRow(nextID+1).getFloat("time")*1000); //get time and convert from seconds to ms
|
nextTimeData=(long)(logdata.getRow(nextID+1).getFloat("time")*1000); //get time and convert from seconds to ms
|
||||||
|
|
||||||
|
@ -290,7 +306,7 @@ void draw() {
|
||||||
nextID+=(loopmillis-nextTimeData)/_timestep* 0.9; //fast forward estimated time steps
|
nextID+=(loopmillis-nextTimeData)/_timestep* 0.9; //fast forward estimated time steps
|
||||||
}
|
}
|
||||||
nextID++;
|
nextID++;
|
||||||
nextID=nextID%logdata.getRowCount();
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,4 +379,39 @@ void draw() {
|
||||||
text(""+(dataErrorCount)+" errors", 5+70*3,12);
|
text(""+(dataErrorCount)+" errors", 5+70*3,12);
|
||||||
|
|
||||||
|
|
||||||
|
if(showTimeline) {
|
||||||
|
tl.drawTL(loopmillis/1000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void mouseClicked()
|
||||||
|
{
|
||||||
|
if (showTimeline)
|
||||||
|
{
|
||||||
|
int temp_timeoffset=(int)(tl.checkMouse(mouseX,mouseY)*1000);
|
||||||
|
if (temp_timeoffset!=0) {
|
||||||
|
|
||||||
|
if (!(nextID+1 < logdata.getRowCount()) && (nextID >= 0)) { //nextID not valid
|
||||||
|
nextID=0; //rest to good value
|
||||||
|
}
|
||||||
|
|
||||||
|
print("Jump nextID from "+nextID);
|
||||||
|
//find nextID to jump to
|
||||||
|
while ((nextID+1 < logdata.getRowCount()) && (nextID >= 0) && (millis()-temp_timeoffset > (long)(logdata.getRow(nextID+1).getFloat("time")*1000))) { //jumped forward
|
||||||
|
nextID++;
|
||||||
|
}
|
||||||
|
print(" over "+nextID);
|
||||||
|
while ((nextID+1 < logdata.getRowCount()) && (nextID >= 0) && (millis()-temp_timeoffset < (long)(logdata.getRow(nextID+1).getFloat("time")*1000))) { //jumped backward
|
||||||
|
nextID--;
|
||||||
|
}
|
||||||
|
println(" to "+nextID);
|
||||||
|
|
||||||
|
timeoffset=temp_timeoffset;
|
||||||
|
newdataforced=true; //force read line for nextID
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue