abstract class Visualization { float value=0; float value2=-1000; PVector posOrigin = new PVector(100,100); float valueMin=0; float valueMax=0; float value2Min=0; //value 2 for twodimensional visualization or second displayed value float value2Max=0; float valueMinRecord = Float.NaN; //nan means no value here float valueMaxRecord = Float.NaN; float value2MinRecord = Float.NaN; //nan means no value here float value2MaxRecord = Float.NaN; boolean showMinMax=false; //default colors (not all used by every implementation) color cmain = color(255,255,255); color cmain2 = color(255,255,255); color cscale = color(100,100,100); color cborder = color(200,200,200); color cmin = color(0,150,0); color cmax = color(150,0,0); color ctext = color(255,255,255); int textsize=12; float textWidthScale=1.0/2*this.textsize/2; //*text.length()* int showdecimals=2; String title=""; String title2=""; String valueUnit=""; String value2Unit=""; public abstract void drawVis(); public void setValue(float pv){ //this.value=constrain(pv,valueMin,valueMax); this.value=pv; if (this.showMinMax){ if (Float.isNaN(this.valueMinRecord) || this.valuethis.valueMaxRecord){ this.valueMaxRecord=this.value; } } } public void setValue2(float pv){ //this.value2=constrain(pv,valueMin,valueMax); this.value2=pv; if (this.showMinMax){ if (Float.isNaN(this.value2MinRecord) || this.value2this.value2MaxRecord){ this.value2MaxRecord=this.value2; } } } public float getValueNormalized() { return (constrain(this.value,this.valueMin,this.valueMax)-this.valueMin)/(this.valueMax-this.valueMin); } public float getValueMinNormalized() { return (constrain(this.valueMinRecord,this.valueMin,this.valueMax)-this.valueMin)/(this.valueMax-this.valueMin); } public float getValueMaxNormalized() { return (constrain(this.valueMaxRecord,this.valueMin,this.valueMax)-this.valueMin)/(this.valueMax-this.valueMin); } public float getValue2Normalized() { return (constrain(this.value2,this.value2Min,this.value2Max)-this.value2Min)/(this.value2Max-this.value2Min); } public float getValue2MinNormalized() { return (constrain(this.value2MinRecord,this.value2Min,this.value2Max)-this.value2Min)/(this.value2Max-this.value2Min); } public float getValue2MaxNormalized() { return (constrain(this.value2MaxRecord,this.value2Min,this.value2Max)-this.value2Min)/(this.value2Max-this.value2Min); } public void setShowMinMax(boolean pshowMinMax){ this.showMinMax = pshowMinMax; } public void setcmain(color pc){ this.cmain=pc; } public void setcmain2(color pc){ this.cmain2=pc; } public void setcscale(color pc){ this.cscale=pc; } public void setcborder(color pc){ this.cborder=pc; } public void setcmin(color pc){ this.cmin=pc; } public void setcmax(color pc){ this.cmax=pc; } public void setctext(color pc){ this.ctext=pc; } public void setTitle(String pt) { this.title=pt; } public void setTitle2(String pt) { this.title2=pt; } public void setValueUnit(String pt) { this.valueUnit=pt; } public void setValue2Unit(String pt) { this.value2Unit=pt; } public void setshowdecimals(int pd) { this.showdecimals=pd; } public String getFormattedValue(double pv){ if( ( (int)(pv*100)/100.0 )%1==0){ return ""+(int)pv; }else{ //has decimals return String.format("%."+this.showdecimals+"f", pv); //limit decimal places } } } public class BarV extends Visualization { PVector size = new PVector(10,100); public BarV(int px, int py, int pw, int ph, float pvmin, float pvmax) { super.valueMin=pvmin; super.valueMax=pvmax; super.posOrigin= new PVector(px,py); //lower left corner this.size = new PVector(pw,ph); //to the right and up } public void drawVis() { rectMode(CORNERS); textSize(super.textsize); fill(super.cmain); noStroke(); rect(super.posOrigin.x,super.posOrigin.y,super.posOrigin.x+this.size.x,super.posOrigin.y-( this.size.y*super.getValueNormalized()) ); if (!Float.isNaN(super.valueMinRecord)){ stroke(super.cmin); line(super.posOrigin.x,super.posOrigin.y-( this.size.y*super.getValueMinNormalized()) ,super.posOrigin.x+this.size.x,super.posOrigin.y-( this.size.y*super.getValueMinNormalized()) ); } if (!Float.isNaN(super.valueMaxRecord)){ stroke(super.cmax); line(super.posOrigin.x, super.posOrigin.y-( this.size.y*super.getValueMaxNormalized()), super.posOrigin.x+this.size.x,super.posOrigin.y-( this.size.y*super.getValueMaxNormalized()) ); } noFill(); stroke(this.cborder); rect(super.posOrigin.x,super.posOrigin.y,super.posOrigin.x+this.size.x,super.posOrigin.y- this.size.y ); //text textAlign(LEFT); fill(super.ctext); text(super.getFormattedValue(super.valueMin)+valueUnit,super.posOrigin.x+this.size.x+1,super.posOrigin.y+super.textsize/2); text(super.getFormattedValue(super.valueMax)+valueUnit,super.posOrigin.x+this.size.x+1,super.posOrigin.y-this.size.y+super.textsize/2); textAlign(LEFT); text(super.getFormattedValue(super.value)+valueUnit,super.posOrigin.x+this.size.x+1,super.posOrigin.y+super.textsize/2-this.size.y/2); //display value //Title textAlign(CENTER); text(super.title, super.posOrigin.x+this.size.x/2, super.posOrigin.y-this.size.y-1); } } public class BarV_cmd extends Visualization { PVector size = new PVector(10,100); public BarV_cmd(int px, int py, int pw, int ph, float pvmin, float pvmax) { super.valueMin=pvmin; super.valueMax=pvmax; super.posOrigin= new PVector(px,py); //lower left corner this.size = new PVector(pw,ph); //to the right and up } public void drawVis() { rectMode(CORNERS); textSize(super.textsize); fill(super.cmain); noStroke(); int zeroy=(int)map(0,super.valueMin,super.valueMax,0,this.size.y); rect(super.posOrigin.x,super.posOrigin.y-zeroy,super.posOrigin.x+this.size.x,super.posOrigin.y-( this.size.y*super.getValueNormalized()) ); if (!Float.isNaN(super.valueMinRecord)){ stroke(super.cmin); line(super.posOrigin.x,super.posOrigin.y-( this.size.y*super.getValueMinNormalized()) ,super.posOrigin.x+this.size.x,super.posOrigin.y-( this.size.y*super.getValueMinNormalized()) ); } if (!Float.isNaN(super.valueMaxRecord)){ stroke(super.cmax); line(super.posOrigin.x, super.posOrigin.y-( this.size.y*super.getValueMaxNormalized()), super.posOrigin.x+this.size.x,super.posOrigin.y-( this.size.y*super.getValueMaxNormalized()) ); } noFill(); stroke(this.cborder); rect(super.posOrigin.x,super.posOrigin.y,super.posOrigin.x+this.size.x,super.posOrigin.y- this.size.y ); line(super.posOrigin.x,super.posOrigin.y-zeroy,super.posOrigin.x+this.size.x,super.posOrigin.y-zeroy); //zero line //text textAlign(LEFT); fill(super.ctext); //text(super.getFormattedValue(super.valueMin),super.posOrigin.x+this.size.x+1,super.posOrigin.y+super.textsize/2); //text(super.getFormattedValue(super.valueMax),super.posOrigin.x+this.size.x+1,super.posOrigin.y-this.size.y+super.textsize/2); textAlign(RIGHT); text(super.getFormattedValue(super.value),super.posOrigin.x+this.size.x/2+super.textWidthScale*3,super.posOrigin.y+super.textsize); //display value textAlign(LEFT); text(valueUnit,super.posOrigin.x+this.size.x/2+super.textWidthScale*3,super.posOrigin.y+super.textsize); //display unit on the right without disturbing alignment //Title textAlign(LEFT); text(super.title, super.posOrigin.x, super.posOrigin.y-this.size.y-1); } } public class BarH extends Visualization { PVector size = new PVector(10,100); public BarH(int px, int py, int pw, int ph,float pvmin, float pvmax) { super.valueMin=pvmin; super.valueMax=pvmax; super.posOrigin= new PVector(px,py); //lower left corner this.size = new PVector(pw,ph); //to the right and up } public void drawVis() { rectMode(CORNERS); textSize(super.textsize); fill(super.cmain); noStroke(); rect(super.posOrigin.x,super.posOrigin.y,super.posOrigin.x+( this.size.x*super.getValueNormalized()),super.posOrigin.y- this.size.y ); if (!Float.isNaN(super.valueMinRecord)){ stroke(super.cmin); line(super.posOrigin.x+( this.size.x*super.getValueMinNormalized()),super.posOrigin.y,super.posOrigin.x+( this.size.x*super.getValueMinNormalized()),super.posOrigin.y- this.size.y ); } if (!Float.isNaN(super.valueMaxRecord)){ stroke(super.cmax); line(super.posOrigin.x+( this.size.x*super.getValueMaxNormalized()),super.posOrigin.y,super.posOrigin.x+( this.size.x*super.getValueMaxNormalized()),super.posOrigin.y- this.size.y ); } noFill(); stroke(super.cborder); rect(super.posOrigin.x,super.posOrigin.y,super.posOrigin.x+this.size.x,super.posOrigin.y- this.size.y ); //text textAlign(LEFT); fill(super.ctext); text(super.getFormattedValue(super.valueMin)+valueUnit,super.posOrigin.x-super.getFormattedValue(super.valueMin).length()*super.textWidthScale,super.posOrigin.y-this.size.y-1); text(super.getFormattedValue(super.valueMax)+valueUnit,super.posOrigin.x+this.size.x-super.getFormattedValue(super.valueMax).length()*super.textWidthScale,super.posOrigin.y-this.size.y-1); text(super.getFormattedValue(super.value)+valueUnit,super.posOrigin.x+this.size.x/2-super.getFormattedValue(super.value).length()*super.textWidthScale,super.posOrigin.y-this.size.y-1); //Title text(super.title, super.posOrigin.x+this.size.x/2-super.title.length()*super.textWidthScale,super.posOrigin.y+this.size.y+1); } } public class BarH_cmd extends Visualization { PVector size = new PVector(10,100); public BarH_cmd(int px, int py, int pw, int ph,float pvmin, float pvmax) { super.valueMin=pvmin; super.valueMax=pvmax; super.posOrigin= new PVector(px,py); //lower left corner this.size = new PVector(pw,ph); //to the right and up } public void drawVis() { rectMode(CORNERS); textSize(super.textsize); int zerox=(int)map(0,super.valueMin,super.valueMax,0,this.size.x); fill(super.cmain); noStroke(); rect(super.posOrigin.x+zerox,super.posOrigin.y,super.posOrigin.x+( this.size.x*super.getValueNormalized()),super.posOrigin.y- this.size.y ); if (!Float.isNaN(super.valueMinRecord)){ stroke(super.cmin); line(super.posOrigin.x+( this.size.x*super.getValueMinNormalized()),super.posOrigin.y,super.posOrigin.x+( this.size.x*super.getValueMinNormalized()),super.posOrigin.y- this.size.y ); } if (!Float.isNaN(super.valueMaxRecord)){ stroke(super.cmax); line(super.posOrigin.x+( this.size.x*super.getValueMaxNormalized()),super.posOrigin.y,super.posOrigin.x+( this.size.x*super.getValueMaxNormalized()),super.posOrigin.y- this.size.y ); } noFill(); stroke(super.cborder); rect(super.posOrigin.x,super.posOrigin.y,super.posOrigin.x+this.size.x,super.posOrigin.y- this.size.y ); //text textAlign(LEFT); fill(super.ctext); //text(super.getFormattedValue(super.valueMin),super.posOrigin.x-super.getFormattedValue(super.valueMin).length()*super.textWidthScale,super.posOrigin.y-this.size.y-1); //text(super.getFormattedValue(super.valueMax),super.posOrigin.x+this.size.x-super.getFormattedValue(super.valueMax).length()*super.textWidthScale,super.posOrigin.y-this.size.y-1); text(super.getFormattedValue(super.value)+valueUnit,super.posOrigin.x+this.size.x/2-super.getFormattedValue(super.value).length()*super.textWidthScale,super.posOrigin.y-this.size.y-1); //Title text(super.title, super.posOrigin.x+this.size.x/2-super.title.length()*super.textWidthScale,super.posOrigin.y+this.textsize+1); } } public class Tacho extends Visualization { int size; public Tacho(int px, int py, int psize, float pvmin, float pvmax) { super.valueMin=pvmin; super.valueMax=pvmax; super.value2Min=pvmin; //same scale super.value2Max=pvmax; //same scale super.posOrigin= new PVector(px,py); //circle center this.size = psize; //radius from the center } public void drawVis() { rectMode(CORNERS); textSize(super.textsize); stroke(super.cmain); float angle=PI-super.getValueNormalized()*PI; //0=right, positive=CCW line(super.posOrigin.x,super.posOrigin.y,super.posOrigin.x+cos(angle)*this.size*0.8 ,super.posOrigin.y-sin(angle)*this.size*0.8); //draw tacho needle if (super.value2!=-1000) { stroke(super.cmain2); float angle2=PI-super.getValue2Normalized()*PI; //0=right, positive=CCW line(super.posOrigin.x,super.posOrigin.y,super.posOrigin.x+cos(angle2)*this.size*0.8 ,super.posOrigin.y-sin(angle2)*this.size*0.8); //draw tacho needle } if (!Float.isNaN(super.valueMinRecord)){ stroke(this.cmin); float angleMin=PI-super.getValueMinNormalized()*PI; //0=right, positive=CCW line(super.posOrigin.x+cos(angleMin)*this.size*0.65 ,super.posOrigin.y-sin(angleMin)*this.size*0.65,super.posOrigin.x+cos(angleMin)*this.size*0.75 ,super.posOrigin.y-sin(angleMin)*this.size*0.75); //draw tacho needle min } if (!Float.isNaN(super.valueMaxRecord)){ stroke(this.cmax); float angleMax=PI-super.getValueMaxNormalized()*PI; //0=right, positive=CCW line(super.posOrigin.x+cos(angleMax)*this.size*0.65 ,super.posOrigin.y-sin(angleMax)*this.size*0.65,super.posOrigin.x+cos(angleMax)*this.size*0.75 ,super.posOrigin.y-sin(angleMax)*this.size*0.75); //draw tacho needle max } stroke(this.cscale); fill(super.ctext); float _steps=0.1; for (float i=0;i<=1+_steps; i+=_steps){ float a=PI-PI*i; line(super.posOrigin.x+cos(a)*this.size*0.85 ,super.posOrigin.y-sin(a)*this.size*0.85 ,super.posOrigin.x+cos(a)*this.size ,super.posOrigin.y-sin(a)*this.size); String _text=super.getFormattedValue(super.valueMin+(super.valueMax-super.valueMin)*i); text(_text,super.posOrigin.x+cos(a)*this.size*1.1-_text.length()*super.textWidthScale-1 ,super.posOrigin.y-sin(a)*this.size*1.1+super.textsize/2-1); } //text fill(super.cmain); text(super.getFormattedValue(super.value)+valueUnit,super.posOrigin.x-super.getFormattedValue(super.value).length()*super.textWidthScale,super.posOrigin.y+super.textsize/2-this.size*0.3); if (super.value2!=-1000) { //value2 is used fill(super.cmain2); text(super.getFormattedValue(super.value2)+value2Unit,super.posOrigin.x-super.getFormattedValue(super.value).length()*super.textWidthScale,super.posOrigin.y+super.textsize/2*4-this.size*0.3); } //Title textAlign(CENTER); fill(super.ctext); text(super.title, super.posOrigin.x, super.posOrigin.y+super.textsize*1.5); if (super.title2!="") { text(super.title2, super.posOrigin.x, super.posOrigin.y+super.textsize*1.5*2); } } } public class Direction extends Visualization { int size; float angleoffset; float minvisiblevalue; float maxvisiblevalue; public Direction(int px, int py, int psize,float pvmin, float pvmax, float pvlmin, float pvlmax, float pangleoffset) { super.valueMin=pvmin; super.valueMax=pvmax; super.posOrigin= new PVector(px,py); //center this.size = psize; //radius from the center super.value2Min=pvlmin; super.value2Max=pvlmax; this.angleoffset=pangleoffset; this.minvisiblevalue=valueMin; this.maxvisiblevalue=valueMax; } public Direction(int px, int py, int psize,float pvmin, float pvmax, float pvlmin, float pvlmax, float pangleoffset, float pminvisiblevalue, float pmaxvisiblevalue) { super.valueMin=pvmin; super.valueMax=pvmax; super.posOrigin= new PVector(px,py); //center this.size = psize; //radius from the center super.value2Min=pvlmin; super.value2Max=pvlmax; this.angleoffset=pangleoffset; this.minvisiblevalue=pminvisiblevalue; this.maxvisiblevalue=pmaxvisiblevalue; } public void drawVis() { rectMode(CORNERS); textSize(super.textsize); stroke(super.cborder); noFill(); if (this.minvisiblevalue==super.valueMin & this.maxvisiblevalue==super.valueMax) { ellipseMode(RADIUS); //centerx, centery, width,height for ellipse ellipse(super.posOrigin.x, super.posOrigin.y, this.size,this.size); }else{ arc(super.posOrigin.x, super.posOrigin.y, this.size*2,this.size*2, this.angleoffset+2*PI -this.minvisiblevalue/super.valueMin*PI, 2*PI+this.angleoffset +this.maxvisiblevalue/super.valueMax*PI, PIE); } stroke(super.cmain); float angle=map(super.getValueNormalized(),0,1,0,2*PI)+this.angleoffset; //float _vecsize=this.size*( (super.value2-super.value2Min)/(super.value2Max-super.value2Min)); float _vecsize=this.size*super.getValue2Normalized(); line(super.posOrigin.x,super.posOrigin.y,super.posOrigin.x+cos(angle)*_vecsize,super.posOrigin.y-sin(angle)*_vecsize); line(super.posOrigin.x+cos(angle-0.1)*_vecsize*0.9,super.posOrigin.y-sin(angle-0.1)*_vecsize*0.9,super.posOrigin.x+cos(angle)*_vecsize,super.posOrigin.y-sin(angle)*_vecsize); //arrow line(super.posOrigin.x+cos(angle+0.1)*_vecsize*0.9,super.posOrigin.y-sin(angle+0.1)*_vecsize*0.9,super.posOrigin.x+cos(angle)*_vecsize,super.posOrigin.y-sin(angle)*_vecsize); //text textAlign(LEFT); fill(super.ctext); text(super.getFormattedValue(super.value)+valueUnit,super.posOrigin.x-super.getFormattedValue(super.value).length()*super.textWidthScale,super.posOrigin.y+super.textsize*1.5*1); if (super.value2