/**
 * CosSinCalc version 6.0.4
 * http://cossincalc.com/
 * 
 * Copyright (c) 2010 Molte Emil Strange Andersen, released under the MIT license.
 */
var CosSinCalc={};CosSinCalc.VERSION="6.0.4";CosSinCalc.Triangle=function(){this.calculate=function(skipStart){var validator=new CosSinCalc.Triangle.Validator(this);var calculator=new CosSinCalc.Triangle.Calculator(this);var validation;if(!skipStart){validation=validator.validate();if(!validation.isValid()){return validation}this.sides.amount=validation.sides.amount;calculator.calculateVariables()}validation=validator.validateCalculation(calculator);if(validation.isValid()){calculator.calculateAdditionalVariables()}return validation};this.resetVariables=function(){this.altitudes={a:null,b:null,c:null};this.medians={a:null,b:null,c:null};this.sides={a:null,b:null,c:null,unit:"degree",amount:0};this.angles={a:null,b:null,c:null,unit:null,bisectors:{a:null,b:null,c:null}};this.alternative=null;this.decimals=2;this.steps=[]};this.each=function(){var callback=arguments[arguments.length-1];var array=(arguments.length>1?arguments[0]:CosSinCalc.Triangle.VARIABLES);for(var i=0,n=array.length;i<n;i++){if(callback(array[i],this.rest(i))==false){return false}}};this.rest=function(index){var array=CosSinCalc.Triangle.VARIABLES.concat();array.splice(index,1);return array};this.copyAsAlternative=function(){this.alternative=new CosSinCalc.Triangle();this.alternative.angles=this.cloneObject(this.angles);this.alternative.sides=this.cloneObject(this.sides);this.alternative.decimals=this.decimals;this.alternative.alternative=this};this.equation=function(latex,v1,v2,v3){var variables=[v1,v2,v3],match,beforeMatch,symbols="",values="";while(latex.length>0){if(match=latex.match(/(\$|@)(\d)/)){beforeMatch=latex.slice(0,match.index);symbols+=beforeMatch;values+=beforeMatch;v=variables[match[2]*1-1];symbols+=(match[1]=="@")?v.toUpperCase():v;values+=(match[1]=="@")?this.formatAngle(this.angles[v],this.angles.unit,this.decimals,true):this.side(v);latex=latex.slice(match.index+2)}else{symbols+=latex;values+=latex;latex=""}}values=values.split("=");values=values[1]+"="+values[0];this.steps.push(symbols+"&\\Rightarrow"+values)};this.formatEquations=function(){return("\\begin{align*}"+this.steps.join("\\\\")+"\\end{align*}")};this.angle=function(variable,value){var undefined;if(value===undefined){return this.formatAngle(this.angles[variable],this.angles.unit,this.decimals)}else{return(this.angles[variable]=this.parseAngle(value,this.angles.unit))}};this.side=function(variable,value){var undefined;if(value===undefined){return this.format(this.sides[variable],this.decimals)}else{return(this.sides[variable]=this.parse(value))}};this.altitude=function(variable){return this.format(this.altitudes[variable],this.decimals)};this.median=function(variable){return this.format(this.medians[variable],this.decimals)};this.anglebisector=function(variable){return this.format(this.angles.bisectors[variable],this.decimals)};this.area=function(){return this.format(this.sides.a*this.sides.b*Math.sin(this.angles.c)/2,this.decimals)};this.circumference=function(){return this.format(this.sides.a+this.sides.b+this.sides.c,this.decimals)};this.resetVariables()};CosSinCalc.Triangle.VARIABLES=["a","b","c"];CosSinCalc.Triangle.ERROR_MESSAGES={notEnoughVariables:"3 values must be specified. Please fill in 3 of the text boxes.",tooManyVariables:"Only 3 values should be specified. Please leave the rest of the text boxes empty.",noSides:"At least one side must be given.",invalidSide:"Only numbers (above zero) are accepted values for a side.",invalidAngle:"Only numbers (above zero) are accepted values for an angle. Furthermore the angle must remain inside the scope of the sum of all angles in the triangle.",invalidTriangle:"The specified values do not match a valid triangle."};CosSinCalc.Parser={parse:function(value){if(value*1===value){return value}if(value==null||value==""){return null}value=value.replace(/[^\d\.,]+/g,"").split(/[^\d]+/);if(value.length>1){value.push("."+value.pop())}return value.join("")*1},parseAngle:function(value,fromUnit){return this.convertAngle(this.parse(value),fromUnit)},degreesToRadians:function(degrees){return Math.PI*degrees/180},gonToRadians:function(gon){return Math.PI*gon/200},radiansToDegrees:function(radians){return 180*radians/Math.PI},radiansToGon:function(radians){return 200*radians/Math.PI},convertAngle:function(value,unit,reverse){if(value==null){return null}switch(unit){case"degree":return(reverse?this.radiansToDegrees(value):this.degreesToRadians(value));case"gon":return(reverse?this.radiansToGon(value):this.gonToRadians(value));default:return value}},round:function(value,decimals){var multiplier=Math.pow(10,decimals);return(Math.round(value*multiplier)/multiplier)},format:function(value,decimals){value=this.round(value,decimals)+"";if(decimals){var index=value.indexOf(".");if(index==-1){value+=".";index=value.length-1}while(value.length-index-1<decimals){value+="0"}}return value},formatAngle:function(value,unit,decimals,isLatex){value=this.format(this.convertAngle(value,unit,true),decimals);switch(unit){case"degree":return(value+(isLatex?"\\textdegree":"°"));case"gon":return(value+(isLatex?"\\text{ gon}":" gon"));default:return(value+(isLatex?"\\text{ rad}":" rad"))}},cloneObject:function(source){var clone={};for(key in source){clone[key]=source[key]}return clone},isAcute:function(value){return(value<Math.PI/2)},isObtuse:function(value){return(value>Math.PI/2)}};CosSinCalc.Triangle.prototype=CosSinCalc.Parser;CosSinCalc.Triangle.Calculator=function(t){this.calculateVariables=function(){switch(t.sides.amount){case 3:calculateThreeAngles();break;case 2:calculateTwoAngles();break;case 1:calculateTwoSides();break;default:return false}return true};this.calculateSideAndAngle=function(){calculateTwoSides()};this.calculateAdditionalVariables=function(){calculateAltitudes();calculateMedians();calculateAngleBisectors()};this.calculateAngle=function(v,rest){return calculateAngleBySides(v,rest)};function calculateThreeAngles(){t.each(function(v,rest){if(!t.angles[v]){t.angles[v]=calculateAngleBySides(v,rest);t.equation("@1=\\arccos\\left(\\frac{$2^2+$3^2-$1^2}{2\\cdot $2\\cdot $3}\\right)",v,rest[0],rest[1])}})}function calculateAngleBySides(v,rest){return Math.acos((square(t.sides[rest[0]])+square(t.sides[rest[1]])-square(t.sides[v]))/(2*t.sides[rest[0]]*t.sides[rest[1]]))}function calculateTwoAngles(){t.each(function(v,rest){if(t.angles[v]){if(!t.sides[v]){t.sides[v]=Math.sqrt(square(t.sides[rest[0]])+square(t.sides[rest[1]])-2*t.sides[rest[0]]*t.sides[rest[1]]*Math.cos(t.angles[v]));t.equation("$1=\\sqrt{$2^2+$3^2-2\\cdot $2\\cdot $3\\cdot \\cos(@1)}",v,rest[0],rest[1]);calculateThreeAngles();return false}t.each(rest,function(v2){if(t.sides[v2]){t.angles[v2]=Math.asin(Math.sin(t.angles[v])*t.sides[v2]/t.sides[v]);t.equation("@2=\\arcsin\\left(\\frac{\\sin(@1)\\cdot $2}{$1}\\right)",v,v2);if(isAmbiguousCase(v,v2)){t.copyAsAlternative();t.alternative.angles[v2]=Math.PI-t.angles[v2];t.alternative.equation("@2="+t.formatAngle(Math.PI,t.angles.unit,t.decimals,true)+"-\\arcsin\\left(\\frac{\\sin(@1)\\cdot $2}{$1}\\right)",v,v2);var alternativeCalculator=new CosSinCalc.Triangle.Calculator(t.alternative);alternativeCalculator.calculateSideAndAngle();t.alternative.calculate(true)}calculateTwoSides();return false}});return false}})}function calculateTwoSides(){calculateLastAngle();t.each(function(v,rest){if(t.sides[v]){t.each(rest,function(v2){if(!t.sides[v2]){t.sides[v2]=Math.sin(t.angles[v2])*t.sides[v]/Math.sin(t.angles[v]);t.equation("$2=\\frac{\\sin(@2)\\cdot $1}{\\sin(@1)}",v,v2)}});return false}})}function calculateLastAngle(){t.each(function(v,rest){if(!t.angles[v]){t.angles[v]=Math.PI-t.angles[rest[0]]-t.angles[rest[1]];t.equation("@1="+t.formatAngle(Math.PI,t.angles.unit,t.decimals,true)+"-@2-@3",v,rest[0],rest[1]);return false}})}function isAmbiguousCase(v1,v2){return(t.isAcute(t.angles[v1])&&t.sides[v1]<t.sides[v2]&&t.sides[v1]>t.sides[v2]*Math.sin(t.angles[v1]))}function square(number){return number*number}function calculateAltitudes(){t.each(function(v,rest){t.altitudes[v]=Math.sin(t.angles[rest[0]])*t.sides[rest[1]]})}function calculateMedians(){t.each(function(v,rest){t.medians[v]=Math.sqrt((2*square(t.sides[rest[0]])+2*square(t.sides[rest[1]])-square(t.sides[v]))/4)})}function calculateAngleBisectors(){t.each(function(v,rest){t.angles.bisectors[v]=Math.sin(t.angles[rest[0]])*t.sides[rest[1]]/Math.sin(t.angles[rest[1]]+t.angles[v]/2)})}};CosSinCalc.Triangle.Validator=function(t){var NOT_ENOUGH_VARIABLES="3 values must be specified. Please fill in 3 of the text boxes.",TOO_MANY_VARIABLES="Only 3 values should be specified. Please leave the rest of the text boxes empty.",NO_SIDES="At least one side must be given.",INVALID_SIDE="Only numbers (above zero) are accepted values for a side.",INVALID_ANGLE="Only numbers (above zero) are accepted values for an angle. Furthermore the angle must remain inside the scope of the sum of all angles in the triangle.",INVALID_TRIANGLE="The specified values do not match a valid triangle.";var validation={sides:{a:null,b:null,c:null,amount:0},angles:{a:null,b:null,c:null,amount:0},exceptions:[],isValid:function(){return(!this.exceptions.length)},total:function(){return(this.sides.amount+this.angles.amount)}};this.validate=function(){t.each(function(v){if(t.sides[v]!=null){validateSide(v)}if(t.angles[v]!=null){validateAngle(v)}});if(validation.isValid()){validateAmount()}return validation};this.validateCalculation=function(calculator){var proceed=t.each(function(v,rest){if(!sideIsValid(t.sides[v])){return false}if(!angleIsValid(t.angles[v])){return false}var validatorAngle=calculator.calculateAngle(v,rest);if(validatorAngle>t.angles[v]+0.01||validatorAngle<t.angles[v]-0.01){return false}});if(proceed==false){raiseException(INVALID_TRIANGLE)}return validation};function validateAmount(){if(validation.total()<3){return raiseException(NOT_ENOUGH_VARIABLES)}if(validation.total()>3){return raiseException(TOO_MANY_VARIABLES)}if(validation.sides.amount<1){return raiseException(NO_SIDES)}}function validateSide(variable){if(sideIsValid(t.sides[variable])){validation.sides.amount++;validation.sides[variable]=true}else{validation.sides[variable]=false;raiseException(INVALID_SIDE)}}function sideIsValid(value){return(!isNaN(value)&&isFinite(value)&&value&&value>0)}function validateAngle(variable){if(angleIsValid(t.angles[variable])){validation.angles.amount++;validation.angles[variable]=true}else{validation.angles[variable]=false;raiseException(INVALID_ANGLE)}}function angleIsValid(value){return(sideIsValid(value)&&value<Math.PI)}function raiseException(message){if(validation.exceptions[validation.exceptions.length-1]!=message){validation.exceptions.push(message)}return validation}};CosSinCalc.Triangle.Drawing=function(t,canvasSize,padding){var coords={};if(!canvasSize){canvasSize=500}if(!padding){padding=25}this.draw=function(container){calculateCoords();resize();invertCoords();applyPadding();var paper=Raphael(container,canvasSize+padding*2,canvasSize+padding*2);var polygon=paper.path("M "+coords.a.join(" ")+" L "+coords.b.join(" ")+" L "+coords.c.join(" ")+" Z");polygon.attr({fill:"#f5eae5",stroke:"#993300","stroke-width":1});drawLabel(paper,coords.a[0],coords.a[1]+10,"A = "+t.angle("a"));drawLabel(paper,coords.b[0],coords.b[1]-10,"B = "+t.angle("b"));drawLabel(paper,coords.c[0],coords.c[1]+10,"C = "+t.angle("c"));drawLabel(paper,(coords.c[0]-coords.b[0])/2+coords.b[0],(coords.c[1]-coords.b[1])/2+coords.b[1],"a = "+t.side("a")).attr("fill","#333");drawLabel(paper,(coords.c[0]-coords.a[0])/2+coords.a[0],coords.a[1],"b = "+t.side("b")).attr("fill","#333");drawLabel(paper,(coords.b[0]-coords.a[0])/2+coords.a[0],(coords.c[1]-coords.b[1])/2+coords.b[1],"c = "+t.side("c")).attr("fill","#333")};function drawLabel(paper,x,y,text){var label=paper.text(x,y,text).attr({"font-size":12,"font-family":"Verdana"});var dimensions=label.getBBox();var background=paper.rect(dimensions.x-4,dimensions.y-2,dimensions.width+8,dimensions.height+4).attr({fill:"#fff","fill-opacity":0.5,stroke:"none"}).insertBefore(label);return label}function calculateCoords(){coords.a=[0,0];coords.c=[t.sides.b,0];coords.b=[Math.sqrt(t.sides.c*t.sides.c-t.altitudes.b*t.altitudes.b),t.altitudes.b];if(t.isObtuse(t.angles.a)){coords.b[0]*=-1;moveCoords()}}function resize(){var width=Math.max(coords.c[0]-coords.b[0],coords.b[0],coords.c[0]);var height=coords.b[1];scaleCoords(canvasSize/Math.max(width,height))}function scaleCoords(scaleFactor){t.each(function(v){coords[v][0]*=scaleFactor;coords[v][1]*=scaleFactor})}function moveCoords(){var distance=coords.b[0]*-1;t.each(function(v){coords[v][0]+=distance})}function invertCoords(){t.each(function(v){coords[v][1]=canvasSize-coords[v][1]})}function applyPadding(){t.each(function(v){coords[v][0]+=padding;coords[v][1]+=padding})}};