> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.zLU$IJZshw$/rev.4461
 * 
 * authors: 
 *   Joshua Lansford

 * license (unless otherwise specified): 
 *   creative commons attribution-share alike 3.0 license.
 *   https://creativecommons.org/licenses/by-sa/3.0/ 
 */ 



// Pressing Control-R will render this sketch.

PFont font;

double fieldPercentage = 0;
double percentageIncrement = .025;
double lagMax = .9;

int width = 500;
int height = 268;


ArrayList shapes = new ArrayList();

double minShapeX = 120;
double maxShapeX = 365;

class Shape{
    double x; double y;
    abstract void draw();
    abstract double hitLine( double yPos );
    abstract double mouseHit( double x, double y );
    
    //Dragging
    boolean locked = false;
    double lockX, lockY;
    void mousePressed(){
        if( mouseHit() ){
            locked = true;
            lockX = mouseX-x;
            lockY = mouseY-y;
        }    
    }
    
    void mouseDragged(){
        if( locked ){
             x = mouseX-lockX;
             y = mouseY-lockY;   
        }
        if( x < minShapeX ) x = minShapeX;
        if( x > maxShapeX ) x = maxShapeX; 
    }
    void mouseReleased(){
        locked = false;
    }
    
    void draw(){
        if( mouseHit() ){
            stroke( #dddddd );
        }else{
            stroke( 0 );
        }
        if( locked ){
            fill( #777777 );
        }else{
            fill( 0 );
        }
    }
}

void mousePressed(){
    for( Shape shape : shapes )shape.mousePressed();    
}
void mouseDragged(){
    for( Shape shape : shapes )shape.mouseDragged();    
}
void mouseReleased(){
    for( Shape shape : shapes) shape.mouseReleased();
}

class Rect extends Shape{
    double size = 30;
    
    public Rect( double newX, double newY, double newSize ){
        x = newX; y = newY; size = newSize;
    }
    void draw(){
        super.draw();
        rect( x, y, size, size );
    }
    double hitLine( double yPos ){
        double result = -1;
        if( yPos > y && yPos < y+size ){
            result = x;
        }
        return result;
    }
    double mouseHit(){
        if( mouseX < x ) return false;
        if( mouseX > x+size ) return false;
        if( mouseY < y ) return false;
        if( mouseY > y+size) return false;
        return true;
    }
}

class Circle extends Shape{
    double size = 30;
    
    public Circle( double newX, double newY, double newSize ){
        x = newX; y = newY; size = newSize;
    }
    void draw(){
        super.draw();
        ellipse( x, y, size, size );
    }
    double hitLine( double yPos ){
        double result = -1;
        if( yPos > y-size/2 && yPos < y+size/2 ){
            result = -sqrt( pow(size/2,2)-pow(yPos-y,2) ) + x;
        }
        return result;
    }
    double mouseHit(){
        return sqrt( pow(mouseX-x,2) + pow( mouseY-y,2 ) ) < size/2;
    }
}

void setup() {  // this is run once.   
    
    // set the background color
    background(255);
    
    // canvas size (Integers only, please.)
    //size(width, height); 
    size( 500, 268 );
      
    // smooth edges
    smooth();
    
    // limit the number of frames per second
    frameRate(30);
    
    // set the width of the line. 
    strokeWeight(1);
    
    // load font
    font = loadFont("FFScala.ttf");
    textFont(font);
    
    shapes.add( new Rect( 72+50+50+20+50, 10+50+80+20, 30 ) );
    shapes.add( new Rect( 80+75+50, 10+50+80, 20 ) );
    shapes.add( new Circle( 300, 70, 25 ) );
    shapes.add( new Circle( 170, 170, 50 ) );
} 

double findHitX( double strokeHeight ){
        //see if this line hits
        double hitX = -1;
        for( Shape shape : shapes ){

            double testHitX = shape.hitLine( strokeHeight );
            if( testHitX > 0 ){
                if( hitX > 0 ){
                    hitX = min( hitX, testHitX );
                }else{
                    hitX = testHitX;
                }
            }
        }
        return hitX;
}

double scopeMaxX = 451;
double scopeMinX = 415;
double scopeMaxY = 195;
double scopeMinY = 221;

void draw() {  // this is run repeatedly.  
    //background
    fill( #ffffff ); stroke( #ffffff );
    rect( 0, 0, width, height );

    // set the width of the line. 
    strokeWeight(1);

    // lenses
    fill( #008D90 );
    stroke( #008D90 );
    ellipse( 120, 82, (136-106), (144-24) );
    ellipse( 368, 82, (136-106), (144-24) );
    fill( #000000 );
    text( "Collimator Lens", 120-20-10-10, 82-40-10-20+5 );
    text( "Focal Lens", 368-20-10, 82-40-10-20+5 );
    
    // laser box
    fill( #0000FF );
    stroke( #0000FF );
    rect( 109, 207, (133-108), (228-207) );
    fill( #000000 );
    text( "Laser", 122-20+5, 241 );
    
    //Receiver
    fill( #0000FF );
    rect( 467, 64, (482-466), (105-64) );
    fill( #000000 ); stroke( 0 );
    text( "Receiver", 467-30+10, 64-5 );
    
    //PC
    //card
    fill( #006500 ); stroke( #006500 );
    rect( 409, 183, (457-409), (227-183) );
    //computer base
    fill( #404040 ); stroke( #404040 );
    rect( 359, 205, (409-359), (227-205) );
    //screen
    fill( #00ffff ); stroke( #00ffff );
    rect( 359, 166, (409-359), (212-166), 10 );
    fill( #000000 ); stroke( 0 );
    text( "PC", 359+10+10-5, 166+50+20+5 );
    
    //Line to PC
    fill( #0000ff ); stroke( #0000ff );
    line( 474, 105, 474, 117 );
    line( 474, 117, 450, 117 );
    line( 450, 117, 450, 142 );
    line( 450, 142, 487, 142 );
    line( 487, 142, 487, 208 );
    line( 487, 208, 458, 208 );
    triangle(466, 134, 481, 142, 466, 149);
    
    
    //Laser
    stroke( #ff0000 );
    line( 120, 207, 23, 83 );
    double lagPercentage = 0; 

    double scopeLastX = 0;
    double scopeLastY = 0;
    
    for( double lagPercentage = 0; 
            lagPercentage < lagMax; 
            lagPercentage += percentageIncrement ){
        int scanPercentage = fieldPercentage-lagPercentage;
        while( scanPercentage < 0 ) scanPercentage += 1;
        double strokeHeight = 
            (fieldBottom-fieldTop)*scanPercentage+fieldTop;
        double alpha = lagPercentage*(0-255)/lagMax+255;
        stroke( 255, 0, 0, alpha );
        line( 23, 83, 120, strokeHeight );
        
        
        double hitX = findHitX(strokeHeight);
        
        //Draw laser
        if( hitX > 0 ){
            line( 120, strokeHeight, hitX, strokeHeight );
        }else{
            line( 120, strokeHeight, 367, strokeHeight );
            line( 367, strokeHeight, 466, 85 );
        }
        
        //draw o-scope
        double scopeX = scanPercentage*(scopeMaxX-scopeMinX)+scopeMinX;
        double scopeY = (hitX > 0)?scopeMaxY:scopeMinY;
        stroke( 181, 230, 29, alpha );
        if( scopeLastX > 0 && scopeX < scopeLastX ){
            line( scopeLastX, scopeLastY, scopeX, scopeY );
        }
        scopeLastX = scopeX;
        scopeLastY = scopeY;
    }
    
    //text( TWO_PI, 20, 20 );
    
    
    //Prism
    double middleX = 13+2;
    double middleY = 77+2;
    double halfWidth = 13-2;
    double cornerWidth = 13-65;
    beginShape();
    for( int virtex = 0; virtex < 8; ++virtex ){
        double angle1 = virtex*TWO_PI/8 + fieldPercentage*(TWO_PI/8)-.3;
        double x = halfWidth*cos( angle1 );
        double y = halfWidth*sin( angle1 );
        vertex( middleX+x, middleY+y );
    }
    endShape();
    fill( #000000 ); stroke( 0 );
    text( "Rotating", 14-10+3, 57-5+2 );
    text( "Mirror", 14-10+3, 67-5+2 );
    
    //Shapes
    for( Shape shape : shapes ){
        shape.draw();
    }
    
    //draw PC measurements
    double measurementX = 362;
    double measurementY = 178;
    boolean lastLightBlocked = false;
    double lastSwitchPercent = -1;
    for( double testPercent = 0; testPercent < 1; testPercent += .01 ){
        double strokeHeight = 
            (fieldBottom-fieldTop)*testPercent+fieldTop;
        boolean lightBlocked = findHitX(strokeHeight) > 0;
        
        if( lightBlocked != lastLightBlocked ){
            if( lastSwitchPercent > 0 ){
                if( !lightBlocked ){
                    fill( 0 );
                }else{
                    fill( #0000ff );
                }
                
                double value = 
                    round((testPercent-lastSwitchPercent)*30*100)/100;
                
                text( value + "mm", measurementX, measurementY );
                measurementY += 11;
            }
            

            lastLightBlocked = lightBlocked;
            lastSwitchPercent = testPercent;
        }

        
        
    }
    
    //stroke( 0 );
    //text( "123mm", measurementX, measurementY );
    
    //animation progression
    fieldPercentage += percentageIncrement;
    if( fieldPercentage > 1 ) fieldPercentage = 0;
    //text( fieldPercentage, 20, 20 );
    
    //fieldPercentage = 0;
}

double fieldTop = 43;
double fieldBottom = 126;