Cohen Sutherland Line Clipping

The HTML file:

<head>
 <script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>
  <script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML"> </script>
 <script type="text/x-mathjax-config">
  MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}});
</script>

 <link rel="stylesheet" href="http://mirkwood.cs.edinboro.edu/~bennett/style/hw.css">
</head>

<body>
<h1>Cohen Sutherland Line Clipping</h1>
<canvas id="canvas" width="400" height="400" style="border:1px solid #000000;"></canvas>

<div id="output">
</div>

<script type="text/javascript" src="clipper.js"></script>
<script type="text/javascript" src="ui.js"></script>

<script type="text/javascript">
"use strict"

let canvas = document.getElementById("canvas");
let ctx = canvas.getContext('2d'); 
canvas.tabIndex = 0;
let width = canvas.width;
let height = canvas.height;

let x0=0,y0=0;
let x1=0, y1=0;

canvas.addEventListener("click", MyHandler);

DrawScene();
</script>

clipper.js

"use strict"

let clipXMin = 25;
let clipYMin = 25;
let clipXMax = 75;
let clipYMax = 75;

let o0, o1;
let text;

function DrawScene() {

    ctx.clearRect(0,0, width, height);

    ctx.save();
    ctx.setTransform(1, 0, 0, -1, 0, height);
    ctx.scale(width/100, height/100);

    ctx.lineWidth = 100/width;


    ctx.setLineDash([2,3]);
    ctx.strokeStyle ="blue";

    ctx.beginPath();
    ctx.moveTo(0,clipYMin);
    ctx.lineTo(100,clipYMin);
    ctx.moveTo(0,clipYMax);
    ctx.lineTo(100,clipYMax);

    ctx.moveTo(clipXMin,0);
    ctx.lineTo(clipXMin,100);
    ctx.moveTo(clipXMax,0);
    ctx.lineTo(clipXMax,100);

    ctx.stroke();
    ctx.setLineDash([]);
    ctx.strokeStyle ="black";

    ctx.lineWidth = ctx.lineWidth * 2;
    ctx.strokeRect(clipXMin, clipYMin, clipXMax-clipXMin, clipYMax-clipYMin);
    ctx.lineWidth = ctx.lineWidth * .5;
    if (state == 1) {
        DrawFirstPoint();
    } else if (state == 2) {
        DrawTheLine();
    }

    ctx.restore();
}

function TextPair(x,y) {
     x = Math.round(x);
     y = Math.round(y);
     return "(" + x.toString() + "," + y.toString() + ") "; 
}

function MakeCode(x,y) {
   let code;
   if (y> clipYMax) {
      code ="1";
   } else {
      code = "0";
   }

   if (y < clipYMin) {
      code = code + "1";
   } else {
      code = code + "0";
   }

   if (x > clipXMax) {
      code = code + "1";
   } else {
      code = code + "0";
   }

   if (x < clipXMin) {
      code = code + "1";
   } else {
      code = code + "0";
   }

   return code;
}


function DrawPoint(x,y, code) {

    ctx.beginPath();
    ctx.arc(x,y, 1, 0, 2*Math.PI);
    ctx.fill();
 
    ctx.save();
    ctx.translate(x,y);
    ctx.font="2pt sans";
    ctx.scale(1,-1);
    ctx.strokeText(code,-4,-4);
    ctx.restore();
}

function DrawLine(x0,y0, x1, y1){
    ctx.beginPath();
    ctx.moveTo(x0,y0);
    ctx.lineTo(x1,y1);
    ctx.stroke();
}


function DrawFirstPoint() {
     o0 =  MakeCode(x0,y0);
     text = "<pre>"
     text += "pt1 " + TextPair(x0,y0) + o0; 
     DrawPoint(x0,y0, o0);
}

function DrawTheLine() {
     o1 = MakeCode(x1, y1);
     DrawPoint(x0,y0,o0);

     text += "\npt2 "+ TextPair(x1,y1) + o1;

     DrawPoint(x1,y1, o1);

     DrawLine(x0,y0, x1, y1);
     DoClip();

     text += "</pre>";

     document.getElementById("output").innerHTML = text ;
}

function Test1() {
    if (o0 == "0000" && o1 == "0000") {

       ctx.strokeStyle = "green";
       DrawLine(x0,y0, x1,y1);
       ctx.strokeStyle = "black";
       text += "\nAccept";

       return true;
    }
    return false;
}

function LERP(s,f,alpha) {
    return s*(1-alpha)+f*alpha;
}

function ClipUD(a1, a2, b1, b2, newy) {
    let alpha = (b2-newy)/(b2-a2);
    let x = LERP(b1,a1, alpha);
    return([x,newy]);
}

function ClipLR(a1, a2, b1, b2, newx) {
    let alpha = (b1-newx)/(b1-a1);
    let y = LERP(b2,a2, alpha);
    return([newx,y]);
}

function RealClip(a1,a2,b1,b2, pos) {
   let value = [0,0];
   switch(pos) {
       case 0:
           text += "\nClip against y="+clipYMax.toString();
           value = ClipUD(a1,a2,b1,b2, clipYMax);
           break;
       case 1:
           text += "\nClip against y="+clipYMin.toString();
           value = ClipUD(a1,a2,b1,b2, clipYMin);
           break;
       case 2:
           text += "\nClip against x="+clipXMax.toString();
           value = ClipLR(a1,a2,b1,b2, clipXMax);
           break
       case 3:
           value = ClipLR(a1,a2,b1,b2, clipXMin);
           text += "\nClip against x="+clipXMin.toString();
           break
   }

   return value;
}

function Clip(a1,a2, b1, b2, code) {
    for(let i=0;i<4;i++) {
        if (code.substring(i,i+1) == "1"){
            let value  = RealClip(a1,a2,b1,b2, i);
            b1 = value[0];
            b2 = value[1];
            code = MakeCode(b1,b2);
            break;
        }
    }
    ctx.fillStyle = "red";
    ctx.strokeStyle = "red";
    DrawPoint(b1,b2,code);
    ctx.fillStyle = "black";
    ctx.strokeStyle = "black";

    return ([b1,b2,code]);
}

function Test3() {
   for(let i = 0; i < 4; i++) {
      if (o0.substring(i,i+1) == "1" && o1.substring(i,i+1)== "1") {
         return true;
      }
   }
   return false;
}

function DoClip() {
    if (Test1() ) {
       return true;
    }

    if (o0=="0000") {
        text += "\nTest 2 passed, keep p1";
        let values = Clip(x0,y0,x1,y1,o1);

        x1 = values[0];
        y1 = values[1];
        o1 = values[2];

        text += "\n\tNew p2 "+ TextPair(x1,y1) + o1;

        DoClip(); 
    }

    if (o1== "0000") {
        text += "\nTest 2 passed, keep p2";
        let values = Clip(x1,y1,x0,y0,o0);

        x0 = values[0];
        y0 = values[1];
        o0 = values[2];

        text += "\n\tNew p1 "+ TextPair(x0,y0) + o0;

        DoClip(); 
    }

    if (Test3()) {
        text += "\n\nTest3 passed ";
        text += "\n\tReject the line, nothing left";
    } else {
        text += "\n\nTest3 Failed ";
        text += "\n\tClip Anything";

        let values = Clip(x0,y0,x1,y1,o1);
        x1 = values[0];
        y1 = values[1];
        o1 = values[2];
        text += "\n\tNew p2 "+ TextPair(x1,y1) + o1;

        DoClip(); 
    }
}

ui.js

"use strict"

let state = 0;

function MyHandler(evnt) {
    switch(state) {
      case 0:
           x0= evnt.offsetX;
           y0 = evnt.offsetY;

           x0 = x0 * 100/width;
           y0 = (height-y0)* 100/width;

           state = 1;
           DrawScene();
           break;
      case 1:
           x1= evnt.offsetX;
           y1 = evnt.offsetY;

           x1 = x1 * 100/width;
           y1 = (height-y1)* 100/width;

           state = 2;
           DrawScene();
           state = 0;
    }

    return;
}