264 lines
7.7 KiB
Plaintext
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
|
|
|
|
////////////////////////////////////////////////////////////////////////// |