block by syntagmatic 6901553

Versor.js Test

Full Screen

Test of C2 in Versor.js by Wesley Smith and Jason Merrill

index.html

<!DOCTYPE html>
<html>
<title>Circle through three points</title>
<script src="versor.js"></script>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<link type="text/css" rel="stylesheet" href="style.css"/>
<style type="text/css">
  
svg {
  background-color: rgba(0, 0, 0, 0.02);
  width: 960px;
  height: 500px;
}

circle {
  stroke: #055;
  fill: none;
  stroke-opacity: .5;
  stroke-width: 0.05;
}

.p1 {
  fill: #f11;
}

.p2 {
  fill: #17f;
}
      
.p3 {
  fill: #1f7;
}
</style>
<div id="GA"></div>
<script>

var C2 = versor.create({
  metric:[1, 1, 1, -1],
  types: [
    { name:"Vec2", bases:["e1", "e2"] },
    { name:"Biv2", bases:["e12"] },
    { name:"Pss", bases:["e1234"] },
    { name:"Rot", bases:["s", "e12"] },
    { name:"Pnt", bases:["e1", "e2", "e3", "e4"], dual:true },
    { name:"Par", bases:["e12", "e13", "e14", "e23", "e24", "e34"] },
    { name:"Dll", bases:["e1", "e2", "e4"], dual:true },
    { name:"Lin", bases:["e134", "e234", "e124"] },
    { name:"Flp", bases:["e14", "e24", "e34"] },
    { name:"Drv", bases:["e14", "e24"] },
    { name:"Tnv", bases:["e13", "e23"] },
    { name:"Dil", bases:["s", "e34"] },
    { name:"Trs", bases:["s", "e14", "e24"] },
    { name:"Mot", bases:["s", "e12", "e14", "e24"] },
    { name:"Bst", bases:["s", "e12", "e13", "e14", "e23", "e24", "e34"] }
  ],
  conformal:true
});

document.addEventListener("DOMContentLoaded", function(evt) {
  var Ori = C2.e3(1);
  var Inf = C2.e4(1);
  var Pss = C2.e1234(1);
  
  function cosh(v) {
    return (Math.exp(v) + Math.exp(-v))*0.5;
  }
  
  function sinh(v) {
    return (Math.exp(v) - Math.exp(-v))*0.5;
  }
  
  
  var Ro = {
    point: function(x, y) {
      return C2.Pnt(x, y, 1, (x*x+y*y)*0.5);
    },
    ipoint: function(x, y) {
      return C2.Pnt(x, y, -1, (x*x+y*y)*0.5);
    },
    circle: function(x, y, r) {
      var s = Ro.point(x, y);
      var r2 = r*r;
      if(r > 0) s[3] -= 0.5*r2;
      else s[3] += 0.5*r2;
      return s;
    },
    size: function(a) {
      var v1 = Inf.ip(a);
      var v2 = a.gp(a.involute()).gp(v1.gp(v1).inverse());
      return a.isdual() ? -v2[0] : v2[0];
    },
    cen: function(a) {
      var v = Inf.ip(a);
      return C2.Pnt(a.gp(Inf).gp(a).div(v.gp(v).gp(-2)));
    },
    // squared distance
    sqd: function(a, b) {
      return -a.ip(b)[0];
    },
    // distance
    dst: function(a, b) {
      return Math.sqrt(Math.abs(Ro.sqd(a, b)));
    },
    split: function(pp) {
      var r = Ro.dst(pp, pp);
      var dlp = C2.e4(-1).ip(pp);
      var bstA = C2.Bst(pp);
      var bstB = C2.Bst(pp);
      bstA[0] -= r;
      bstB[0] += r;
      var pA = C2.Pnt(bstA.div(dlp));
      var pB = C2.Pnt(bstB.div(dlp));
      return [pA, pB];
    }
  };
  
  var Fl = {
    dir: function(a) {
      return a.isdual() ?
      C2.e4(-1).op(a) :
      C2.e4(-1).ip(a);
    },
    loc: function(a, p) {
      if(a.isdual()) return C2.Pnt(p.op(a).div(a));
      else return C2.Pnt(p.ip(a).div(a));
    }
  };
  
  var Op = {
    trs: function(x, y) {
      return C2.Trs(1, 0.5*x, 0.5*y);
    },
    bst: function(pp) {
      var norm;
      var sz = pp.ip(pp)[0];
      
      var cn, sn;
      if(sz < 0) {
        norm = Math.sqrt(-sz);
        cn = cosh(norm);
        sn = -sinh(norm);
      }
      else if(sz > 0) {
        norm = Math.sqrt(sz);
        cn = cosh(norm);
        sn = -sinh(norm);
      }
      else {
        cn = 1;
        sn = -1;
      }
      var res = C2.Bst(pp.gp(sn));
      res[0] = cn;
      return res;
    }
  };
  
  
  function dual(a) {
    return a.gp(Pss);
  }
  
  function normalizePoint(p) {
    return p.gp(1/p[2]);
  }
  
  function dist(p1, p2) {
    var dx = p1[0]-p2[0];
    var dy = p1[1]-p2[1];
    return Math.sqrt(dx*dx+dy*dy);
  }
  
  function circleRadius(c) {
    return Math.sqrt(Math.abs(Ro.size(c, true)));
  }
  
  function circleX(c) {
    return Ro.cen(c)[0];
  }
  
  function circleY(c) {
    return Ro.cen(c)[1];
  }
  
  
  var N=40;
  var scale=20;
  var w=600;
  var h=600;
  var svg = d3.select("#GA").append("svg:svg")
  .attr("width", w)
  .attr("height", h);

  function canvasToWorld(p) {
    return [
    (p[0]-w/2)/scale,
    (p[1]-h/2)/-scale
    ];
  }
  
  // draw a C2 circle in an SVG using D3
  function d3Circle(sel) {
    return sel.attr("r", circleRadius)
    .attr("cx", circleX)
    .attr("cy", circleY);
  }
  
  var p1 = Ro.point(1, 1);
  var p2 = Ro.point(-5, 0);
  var p3 = Ro.point(0, 5);
  var circleThrough = p1.op(p2).op(p3);
  
  var drag = (function() {
    var dragPoint;
    var drag = d3.behavior.drag()
    .on('dragstart', function(){
      var pos = canvasToWorld(d3.mouse(this));
      var smallestDist = 3/scale;

      dragPoint = undefined;
      var thisDist = dist(pos, p1);
      if (thisDist < smallestDist) {
        dragPoint = "p1";
        smallestDist = thisDist;
      }
      thisDist = dist(pos, p2);
      if (thisDist < smallestDist) {
        dragPoint = "p2";
        smallestDist = thisDist;
      }
      thisDist = dist(pos, p3);
      if (thisDist < smallestDist) {
        dragPoint = "p3";
        smallestDist = thisDist;
      }
    })
    .on('drag', function(){
      if (!dragPoint) return;
      var pos = canvasToWorld(d3.mouse(this));
      switch (dragPoint) {
        case "p1": p1 = Ro.point(pos[0], pos[1]); break;
        case "p2": p2 = Ro.point(pos[0], pos[1]); break;
        case "p3": p3 = Ro.point(pos[0], pos[1]); break;
      }

      var circleThrough = p1.op(p2).op(p3);

      var sel;
      
      sel = g.selectAll(".generator").data([p1, p2, p3]);
      sel.attr("cx", function(d) { return d[0]; })
      .attr("cy", function(d) { return d[1]; });

      sel = g.selectAll(".elements").data([circleThrough]);
      d3Circle(sel);
    });
    return drag;
  })();

  svg.call(drag);


  g = svg.append("svg:g")
  .attr("transform", "translate("+(w/2)+", "+(h/2)+") scale("+scale+", "+(-scale)+")");

  var sel = g.selectAll(".elements").data([circleThrough])
    .enter().append("svg:circle")
    .attr("class", "elements");
    d3Circle(sel);

  g.selectAll(".generator").data([p1, p2, p3])
    .enter().append("svg:circle")
    .attr("class", function(d, i) { return "generator p"+(i+1); })
    .attr("cx", function(d) { return d[0]; })
    .attr("cy", function(d) { return d[1]; })
    .attr("r", function(d) { return 3/scale; });

}, false);

</script>
</html>