/*
EZ VectorGraphics library by Dheera Venkatraman
Copyright (C) 2006.
Purposes:
1. Browser-independent vector graphics rendering (VML in IE, SVG in FF)
2. A simple wireframe 3D renderer
A lot of bugs and improvements need to be worked out
in this version, so I would advise you to NOT COPY AND USE this script.
However if you're interested in helping develop it, and ultimately releasing
it under GPL, let me know.
*/

var ezvg_browser='';

if(navigator.userAgent.toLowerCase().indexOf('opera')!=-1) ezvg_browser='opera';
else if(navigator.userAgent.toLowerCase().indexOf('gecko')!=-1) ezvg_browser='firefox';
else if(navigator.userAgent.toLowerCase().indexOf('msie')!=-1) ezvg_browser='msie';
else if(navigator.userAgent.toLowerCase().indexOf('safari')!=-1) ezvg_browser='safari';

var ezvg_usesvg=0;
var ezvg_usevml=0;
var ezvg_usecanvas=0;

if(ezvg_browser=='opera') ezvg_usesvg=1;
else if(ezvg_browser=='firefox') ezvg_usesvg=1;
else if(ezvg_browser=='safari') ezvg_usecanvas=1;
else if(ezvg_browser=='msie') ezvg_usevml=1;

var ezvg_svg="http://www.w3.org/2000/svg";
var ezvg_xhtml="http://www.w3.org/1999/xhtml";

function ezvg(id,cwidth,cheight,wnd) {
this.desc="";
this.canvas=null;
this.color='#000000';
this.strokewidth=1;
this.container=null;

this.setcolor = new Function('arg','this.color=arg.toLowerCase();this.desc+="setcolor|"+arg.toLowerCase()+"\\n";');
this.setstrokewidth = new Function('arg','this.strokewidth=arg.toLowerCase();this.desc+="setstrokewidth|"+arg.toLowerCase()+"\\n";');

this.init=function() {
this.container=document.getElementById(id);
if(ezvg_usevml) {
document.write('<style>v\:*{behavior:url(#VMLRender);position:absolute;}</style>');
document.write('<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />');
document.write('<object id="VMLRender" codebase="vgx.dll" classid="CLSID:10072CEC-8CC1-11D1-986E-00A0C955B42E">');
document.write('</object>');
}
if(ezvg_usesvg) {
var node;
node=document.createElementNS(ezvg_svg,'svg');
node.setAttribute('id','plot');
node.setAttribute('viewbox','0 0 '+cwidth+' '+cheight);
node.setAttribute('style','width:'+cwidth+'px;height:'+cheight+'px;position:absolute;top:0px;left:0px;');
this.container.appendChild(node);
this.canvas=node;
}
}

this.line=function(x1,y1,x2,y2) {
if(ezvg_usevml) {
this.container.innerHTML+='<v:line from="'+x1+','+y1+'" to='+x2+','+y2+'" strokecolor="'+this.color+'" strokewidth="'+this.strokewidth+'" />';
}
if(ezvg_usesvg) {
var node;
node = document.createElementNS(ezvg_svg,'line');
node.setAttributeNS(null,'x1',x1);
node.setAttributeNS(null,'y1',y1);
node.setAttributeNS(null,'x2',x2);
node.setAttributeNS(null,'y2',y2);
node.setAttributeNS(null,'stroke',this.color);
node.setAttributeNS(null,'stroke-width',this.strokewidth);
node.setAttributeNS(null,'shape-rendering','optimizeSpeed');
this.canvas.appendChild(node);
}
this.desc+="line|"+x1+"|"+y1+"|"+x2+"|"+y2+"\n";
}

this.rect = function(x,y,width,height) {
if(ezvg_usevml) {
this.container.innerHTML+='<v:rect filled="false" style="width:'+width+';height:'+height+';top:'+y+';left:'+x+';" />';
}
if(ezvg_usesvg) {
var node;
node = document.createElementNS(ezvg_svg,'rect');
node.setAttributeNS(null,'x',x);
node.setAttributeNS(null,'y',y);
node.setAttributeNS(null,'width',width);
node.setAttributeNS(null,'height',height);
node.setAttributeNS(null,'fill','none');
node.setAttributeNS(null,'stroke',this.color);
node.setAttributeNS(null,'stroke-width',this.strokewidth);
this.canvas.appendChild(node);
}
this.desc+="rect "+x+" "+y+" "+width+" "+height+"\n";
}

this.createselrect = function(x,y,width,height) {
if(ezvg_usevml) {
this.container.innerHTML+='<v:rect id="selrect" filled="false" style="width:'+width+';height:'+height+';top:'+y+';left:'+x+';" />';
return "selrect";
}
if(ezvg_usesvg) {
var node;
node = document.createElementNS(ezvg_svg,'rect');
node.setAttributeNS(null,'x',x);
node.setAttributeNS(null,'y',y);
node.setAttributeNS(null,'width',width);
node.setAttributeNS(null,'height',height);
node.setAttributeNS(null,'fill','none');
node.setAttributeNS(null,'stroke',this.color);
node.setAttributeNS(null,'stroke-width',this.strokewidth);
this.canvas.appendChild(node);
return node;
}
}

this.setselrect = function(node,x,y,width,height) {
if(ezvg_usevml) {
document.getElementById(node).style.left=x;
document.getElementById(node).style.top=y;
document.getElementById(node).style.width=width;
document.getElementById(node).style.height=height;
}
if(ezvg_usesvg) {
node.setAttributeNS(null,'x',x);
node.setAttributeNS(null,'y',y);
node.setAttributeNS(null,'width',width);
node.setAttributeNS(null,'height',height);
node.setAttributeNS(null,'stroke',this.color);
node.setAttributeNS(null,'stroke-width',this.strokewidth);
}
}

this.text = function(x,y,text,font,size) {
this.desc+="text|"+x+"|"+y+"|"+text+"|"+font+"|"+size+"\n";
if(ezvg_usevml) {
this.container.innerHTML+='<div unselectable="on" style="position:absolute;top:'+(y-size-2)+';left:'+x+';height:'+size+';font-family:'+font+';font-size:'+size+'px;">'+text+'</div>';
}
if(ezvg_usesvg) {
var node;
var node2;
node = document.createElementNS(ezvg_svg,'text');
node2 = document.createTextNode(text);
node.setAttributeNS(null,'x',x);
node.setAttributeNS(null,'y',y);
node.setAttributeNS(null,'font-size',size);
node.setAttributeNS(null,'font-family',font);
node.appendChild(node2);
this.canvas.appendChild(node);
return node;
}
}

this.getdesc = function() {
  return this.desc;
}

this.polyline = function(xpoints,ypoints) {
var points="";
for(i=0;i<xpoints.length;i++) {
points+=" "+xpoints[i]+","+ypoints[i];
}
if(ezvg_usevml) {
this.container.innerHTML+='<v:polyline unselectable="on" points="'+points+'" filled="false" strokecolor="'+this.color+'" strokeweight="'+this.strokewidth+'"/>';
}
if(ezvg_usesvg) {
var node;
node = document.createElementNS(ezvg_svg,'polyline');
node.setAttributeNS(null,'fill','none');
node.setAttributeNS(null,'points',points);
node.setAttributeNS(null,'stroke',this.color);
node.setAttributeNS(null,'stroke-width',this.strokewidth);
node.setAttributeNS(null,'shape-rendering','optimizeSpeed');
this.canvas.appendChild(node);
}
this.desc+="polyline|"+points+"\n";
}

this.clear = function() {
if(ezvg_usevml) {
this.container.innerHTML="";
}
if(ezvg_usesvg) {
while(this.canvas.hasChildNodes()) {
this.canvas.removeChild(this.canvas.firstChild);
}
}
this.desc="";
}
}

function ezvgcamera() {
this.pa=null;
this.pb=null;
this.pc=null;
this.pd=null;
this.po=null;
this.hx=null;
this.hy=null;
this.hz=null;
this.hp=null;
this.cxx=null;
this.cxy=null;
this.cxz=null;
this.cyx=null;
this.cyy=null;
this.cyz=null;
/* sets the camera location by given an array [a,b,c,d] corresponding to the camera image plane ax+by+cz+d=0 */
this.setcameralocation = function(abcdv) {
var pa=abcdv[0];
var pb=abcdv[1];
var pc=abcdv[2];
var pd=abcdv[3];
this.pa=pa;
this.pb=pb;
this.pc=pc;
this.pd=pd;
/* convert to hessian normal form */
this.hx=pa/Math.sqrt(pa*pa+pb*pb+pc*pc);
this.hy=pb/Math.sqrt(pa*pa+pb*pb+pc*pc);
this.hz=pc/Math.sqrt(pa*pa+pb*pb+pc*pc);
this.hp=pd/Math.sqrt(pa*pa+pb*pb+pc*pc);
}

this.setcameraorientation = function(v) {
/* guess y axis of camera in plane */
var icyx=-v[0];
var icyy=-v[1];
var icyz=-v[2];
/* get unnormalized camera x axis */
this.cxx=icyy*this.hz-icyz*this.hy;
this.cxy=icyz*this.hx-icyx*this.hz;
this.cxz=icyx*this.hy-icyy*this.hx;
/* normalize camera x axis */
var cxn=Math.sqrt(this.cxx*this.cxx+this.cxy*this.cxy+this.cxz*this.cxz);
this.cxx=this.cxx/cxn;
this.cxy=this.cxy/cxn;
this.cxz=this.cxz/cxn;
/* get real camera y axis */
this.cyx=this.cxy*this.hz-this.cxz*this.hy;
this.cyy=this.cxz*this.hx-this.cxx*this.hz;
this.cyz=this.cxx*this.hy-this.cxy*this.hx;

this.po=this.getsmack(new Array(0,0,0)); /* where is the origin on the camera? */
}

this.getcameraorientation = function() {
return new Array(this.cyx,this.cyy,this.cyz);
}

this.getcameraorientationorth = function() {
return new Array(this.cxx,this.cxy,this.cxz);
}

/* returns an arary [x,y,z,p] of the camera image plane in hessian normal form */
/* and p is the distance to the plane */
this.getcameralocation = function() {
return new Array(this.hx,this.hy,this.hz,this.hp);
}

/* function mostly for internal use that determines the 3-d location that a ray from a 3-d point
smacks into the camera image plane */
this.getsmack = function(qv) {
var u=(this.pa*qv[0]+this.pb*qv[1]+this.pc*qv[2]+this.pd)/(this.pa*this.hx+this.pb*this.hy+this.pc*this.hz);
var ix=qv[0]-u*this.hx;
var iy=qv[1]-u*this.hy;
var iz=qv[2]-u*this.hz;
return new Array(ix,iy,iz);
}

/* this is probably the function you want. takes a 3-d vector v and */
/* gives you a 2-d vector as to where the point is in the camera image */
this.getprojection = function(qv) {
var u=(this.pa*qv[0]+this.pb*qv[1]+this.pc*qv[2]+this.pd)/(this.pa*this.hx+this.pb*this.hy+this.pc*this.hz);
var ix=qv[0]-u*this.hx-this.po[0];
var iy=qv[1]-u*this.hy-this.po[1];
var iz=qv[2]-u*this.hz-this.po[2];
var projx=-(ix*this.cxx+iy*this.cxy+iz*this.cxz); /* so that mathematical axis convention sees RH coord sys */
var projy=ix*this.cyx+iy*this.cyy+iz*this.cyz;
return new Array(projx,projy);
}
}


