Files
ESP32/DCC-Centrale/Firmware/Controller/DCCpp_Controller/dTracks.pde
2026-02-10 11:05:54 +01:00

264 lines
7.7 KiB
Plaintext

//////////////////////////////////////////////////////////////////////////
// DCC++ CONTROLLER: Classes for Layouts and Tracks
//
// Layout - defines a scaled region on the screen into which tracks
// will be place using scaled coordinates
//
// Track - defines a curved or straight piece of track.
// - placement on layout can be in absolute scaled coordinates
// or linked to one end of a previously-defined track.
// - tracks can be linked even across separate layouts
// - define multiple overlapping tracks to create any type
// of turnout, crossover, or other complex track
//////////////////////////////////////////////////////////////////////////
class Layout{
int xCorner, yCorner;
float sFactor;
Layout(int xCorner, int yCorner, int frameWidth, float layoutWidth, float layoutHeight){
this.xCorner=xCorner;
this.yCorner=yCorner;
sFactor=float(frameWidth)/layoutWidth; // frameWidth in pixels, layoutWidth in mm, inches, cm, etc.
} // Layout
Layout(Layout layout){
this.xCorner=layout.xCorner;
this.yCorner=layout.yCorner;
this.sFactor=layout.sFactor;
} // Layout
void copy(Layout layout){
this.xCorner=layout.xCorner;
this.yCorner=layout.yCorner;
this.sFactor=layout.sFactor;
} // copy
boolean equals(Layout layout){
return((this.xCorner==layout.xCorner)&&(this.yCorner==layout.yCorner)&&(this.sFactor==layout.sFactor));
} // equals
} // Layout Class
//////////////////////////////////////////////////////////////////////////
class Track extends DccComponent{
float[] x = new float[2];
float[] y = new float[2];
float[] a = new float[2];
color tColor;
float xR, yR;
float r;
float aStart, aEnd;
int tStatus=1; // specfies current track status (0=off/not visible, 1=on/visible)
int hStatus=0; // specifies if current track is highlighted (1) or normal (0)
Layout layout;
Track(Layout layout, float x, float y, float tLength, float angleDeg){
this.x[0]=x;
this.y[0]=y;
this.a[1]=angleDeg/360.0*TWO_PI;
this.a[0]=this.a[1]+PI;
if(this.a[0]>=TWO_PI)
this.a[0]-=TWO_PI;
this.x[1]=this.x[0]+cos(this.a[1])*tLength;
this.y[1]=this.y[0]-sin(this.a[1])*tLength;
this.layout=layout;
this.tColor=color(255,255,0);
dccComponents.add(this);
} // Track - straight, absolute
//////////////////////////////////////////////////////////////////////////
Track(Track track, int trackPoint, float tLength, Layout layout){
this.x[0]=track.x[trackPoint%2];
this.y[0]=track.y[trackPoint%2];
this.a[1]=track.a[trackPoint%2];
this.a[0]=this.a[1]+PI;
if(this.a[0]>=TWO_PI)
this.a[0]-=TWO_PI;
this.x[1]=this.x[0]+cos(this.a[1])*tLength;
this.y[1]=this.y[0]-sin(this.a[1])*tLength;
this.layout=layout;
this.tColor=color(255,255,0);
dccComponents.add(this);
} // Track - straight, relative, Layout specified
//////////////////////////////////////////////////////////////////////////
Track(Track track, int trackPoint, float tLength){
this.x[0]=track.x[trackPoint%2];
this.y[0]=track.y[trackPoint%2];
this.a[1]=track.a[trackPoint%2];
this.a[0]=this.a[1]+PI;
if(this.a[0]>=TWO_PI)
this.a[0]-=TWO_PI;
this.x[1]=this.x[0]+cos(this.a[1])*tLength;
this.y[1]=this.y[0]-sin(this.a[1])*tLength;
this.layout=track.layout;
this.tColor=color(255,255,0);
dccComponents.add(this);
} // Track - straight, relative, no Layout specified
//////////////////////////////////////////////////////////////////////////
Track(Layout layout, float x, float y, float curveRadius, float curveAngleDeg, float angleDeg){
float thetaR, thetaA;
int d;
thetaR=curveAngleDeg/360.0*TWO_PI;
thetaA=angleDeg/360.0*TWO_PI;
d=(thetaR>0)?1:-1;
this.x[0]=x;
this.y[0]=y;
this.a[0]=thetaA+PI;
if(this.a[0]>=TWO_PI)
this.a[0]-=TWO_PI;
this.a[1]=thetaA+thetaR;
if(this.a[1]>=TWO_PI)
this.a[1]-=TWO_PI;
if(this.a[1]<0)
this.a[1]+=TWO_PI;
this.r=curveRadius;
this.xR=this.x[0]-d*this.r*sin(thetaA);
this.yR=this.y[0]-d*this.r*cos(thetaA);
this.x[1]=this.xR+d*this.r*sin(thetaA+thetaR);
this.y[1]=this.yR+d*this.r*cos(thetaA+thetaR);
if(d==1){
this.aEnd=PI/2-thetaA;
this.aStart=this.aEnd-thetaR;
}else{
this.aStart=1.5*PI-thetaA;
this.aEnd=this.aStart-thetaR;
}
this.layout=layout;
this.tColor=color(255,255,0);
dccComponents.add(this);
} // Track - curved, absolute
//////////////////////////////////////////////////////////////////////////
Track(Track track, int trackPoint, float curveRadius, float curveAngleDeg, Layout layout){
float thetaR, thetaA;
int d;
thetaR=curveAngleDeg/360.0*TWO_PI;
thetaA=track.a[trackPoint%2];
d=(thetaR>0)?1:-1;
this.x[0]=track.x[trackPoint%2];
this.y[0]=track.y[trackPoint%2];
this.a[0]=thetaA+PI;
if(this.a[0]>=TWO_PI)
this.a[0]-=TWO_PI;
this.a[1]=thetaA+thetaR;
if(this.a[1]>=TWO_PI)
this.a[1]-=TWO_PI;
if(this.a[1]<0)
this.a[1]+=TWO_PI;
this.r=curveRadius;
this.xR=this.x[0]-d*this.r*sin(thetaA);
this.yR=this.y[0]-d*this.r*cos(thetaA);
this.x[1]=this.xR+d*this.r*sin(thetaA+thetaR);
this.y[1]=this.yR+d*this.r*cos(thetaA+thetaR);
if(d==1){
this.aEnd=PI/2-thetaA;
this.aStart=this.aEnd-thetaR;
}else{
this.aStart=1.5*PI-thetaA;
this.aEnd=this.aStart-thetaR;
}
this.layout=layout;
this.tColor=color(255,255,0);
dccComponents.add(this);
} // Track - curved, relative, Layout specified
//////////////////////////////////////////////////////////////////////////
Track(Track track, int trackPoint, float curveRadius, float curveAngleDeg){
float thetaR, thetaA;
int d;
thetaR=curveAngleDeg/360.0*TWO_PI;
thetaA=track.a[trackPoint%2];
d=(thetaR>0)?1:-1;
this.x[0]=track.x[trackPoint%2];
this.y[0]=track.y[trackPoint%2];
this.a[0]=thetaA+PI;
if(this.a[0]>=TWO_PI)
this.a[0]-=TWO_PI;
this.a[1]=thetaA+thetaR;
if(this.a[1]>=TWO_PI)
this.a[1]-=TWO_PI;
if(this.a[1]<0)
this.a[1]+=TWO_PI;
this.r=curveRadius;
this.xR=this.x[0]-d*this.r*sin(thetaA);
this.yR=this.y[0]-d*this.r*cos(thetaA);
this.x[1]=this.xR+d*this.r*sin(thetaA+thetaR);
this.y[1]=this.yR+d*this.r*cos(thetaA+thetaR);
if(d==1){
this.aEnd=PI/2-thetaA;
this.aStart=this.aEnd-thetaR;
}else{
this.aStart=1.5*PI-thetaA;
this.aEnd=this.aStart-thetaR;
}
this.layout=track.layout;
this.tColor=color(255,255,0);
dccComponents.add(this);
} // Track - curved, relative, no Layout specified
//////////////////////////////////////////////////////////////////////////
void display(){
if(tStatus==1){ // track is visible
if(hStatus==1) // track is highlighted
stroke(color(0,255,0));
else
stroke(color(255,255,0));
} else{ // track is not visible
if(hStatus==1) // track is highlighted
stroke(color(255,0,0));
else
stroke(color(80,80,0));
}
strokeWeight(3);
ellipseMode(RADIUS);
noFill();
if(r==0){
line(x[0]*layout.sFactor+layout.xCorner,y[0]*layout.sFactor+layout.yCorner,x[1]*layout.sFactor+layout.xCorner,y[1]*layout.sFactor+layout.yCorner);
}
else{
arc(xR*layout.sFactor+layout.xCorner,yR*layout.sFactor+layout.yCorner,r*layout.sFactor,r*layout.sFactor,aStart,aEnd);
}
} // display()
} // Track Class
//////////////////////////////////////////////////////////////////////////