var powers=new Array();var peakTorque=new Array();var peakPower=new Array();var peakTorqueRpm=new Array();var peakPowerRpm=new Array();var distanceAtInstants=new Array();var speedAtInstants=new Array();var accelerationAtInstants=new Array();var commonMinSpeed;var commonMaxSpeed;var optGears=new Array();var maxTimes=new Array();var maxTime;var airDragFactor=new Array();var totalWeight=new Array();var topSpeed=new Array();var minSpeed=new Array();var a_30_60=new Array();var a_30_90=new Array();var a_30_120=new Array();var a_60_90=new Array();var a_60_120=new Array();var bestShiftRpms;var bestStartGear;var cruisingRpm=new Array();var dynoInGear=new Array();var gap;var gapLabel;var bestShiftRpmsForAllCars=new Array();var timeStep=50;var accFactor=18.7;var hpCalcFactor=0.000191;var airDragConst=0.0033;var accelerationFraudFactor=1.0;function putWaitMessage(){var progressMessage="Performing Calculations...";var buttonHtml="<INPUT type='button' name='calculate' value='"+progressMessage+"' disabled='1' width='100'>";buttonHtml+="<BR><BR><FONT color='#0000FF'>The calculations take about 30s to complete.  Please wait...</FONT>";document.getElementById('calculate_button').innerHTML=buttonHtml;}function calculate(){putWaitMessage();setTimeout('calculateMain()',10);}function calculateMain(){content="";content+="<INPUT type='button' name='back' value='<< Edit Inputs' onClick='draw()'>";for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}
dynoInGear[car]=4;
saveTorque(car);
totalWeight[car]=parseFloat(g_weight[car])+parseFloat(driverWeight[car]);
airDragFactor[car]=airDragConst*parseFloat(dragCoefficients[car])*parseFloat(frontalAreas[car]);
topSpeed[car]=parseFloat(findMaxSpeed(car));
minSpeed[car]=parseFloat(findMinSpeed(car));
findCommonMinMaxSpeeds();
findCruisingRpm(car);
var tmpPower=new Array();peakPower[car]=0;peakTorque[car]=0;for(var r=parseInt(minRpm[car]);r<=parseInt(maxRpm[car]);r=r+parseInt(stepRpm[car])){tmpPower[r]=Math.round(parseInt(torques[car][r])*parseInt(r)*hpCalcFactor);if(torques[car][r]>=peakTorque[car]){peakTorque[car]=torques[car][r];peakTorqueRpm[car]=r;}if(tmpPower[r]>=peakPower[car]){peakPower[car]=tmpPower[r];peakPowerRpm[car]=r;}}powers[car]=tmpPower;}
computeAccelTimes();
speedTimeCalculations();
calculateGap();content+="<BR><BR><TABLE>";content+="<TR><TD class='indexKey'>Performance Charts</TD></TR>";content+="<TR><TD id='performance_chart'></TD></TR>";content+="<TR><TD class='indexKey'>Performance Metrics</TD></TR>";content+="<TR><TD id='performance_table'></TD></TR>";content+="</TABLE>";content+="<BR><INPUT type='button' name='back' value='<< Edit Inputs' onClick='draw()'>";document.getElementById('top').innerHTML=content;drawPerformanceCharts("performance_chart");drawPerformanceTable("performance_table");}function findCruisingRpm(car){cruisingRpm[car]=getRpmAtSpeed(80,numGears[car],car);}function findCommonMinMaxSpeeds(){commonMinSpeed=-1;commonMaxSpeed=-1;for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}if((commonMinSpeed==-1)||(minSpeed[car]>commonMinSpeed)){commonMinSpeed=minSpeed[car];}if((commonMaxSpeed==-1)||(topSpeed[car]<commonMaxSpeed)){commonMaxSpeed=topSpeed[car];}}}function computeAccelTimes(){for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}if((minSpeed[car]>30)||(topSpeed[car]<60)){a_30_60="-";}else{findOptGears(car,30,60);a_30_60[car]=parseFloat(maxTimes[car])/1000;a_30_60[car]+="<BR><I><FONT color='#333333'>Start in gear "+bestStartGear+"</FONT></I>";for(var i in bestShiftRpms){var temp=parseInt(i)+1;a_30_60[car]+="<BR><I><FONT color='#333333'>Shift gear "+i+" to "+temp+" @ "+Math.round(bestShiftRpms[i])+" RPM</FONT></I>";}};if((minSpeed[car]>30)||(topSpeed[car]<90)){a_30_90="-";}else{findOptGears(car,30,90);a_30_90[car]=parseFloat(maxTimes[car])/1000;a_30_90[car]+="<BR><I><FONT color='#333333'>Start in gear "+bestStartGear+"</FONT></I>";for(var i in bestShiftRpms){var temp=parseInt(i)+1;a_30_90[car]+="<BR><I><FONT color='#333333'>Shift gear "+i+" to "+temp+" @ "+Math.round(bestShiftRpms[i])+" RPM</FONT></I>";}};if((minSpeed[car]>30)||(topSpeed[car]<120)){a_30_120="-";}else{findOptGears(car,30,120);a_30_120[car]=parseFloat(maxTimes[car])/1000;a_30_120[car]+="<BR><I><FONT color='#333333'>Start in gear "+bestStartGear+"</FONT></I>";for(var i in bestShiftRpms){var temp=parseInt(i)+1;a_30_120[car]+="<BR><I><FONT color='#333333'>Shift gear "+i+" to "+temp+" @ "+Math.round(bestShiftRpms[i])+" RPM</FONT></I>";}};if((minSpeed[car]>60)||(topSpeed[car]<90)){a_60_90="-";}else{findOptGears(car,60,90);a_60_90[car]=parseFloat(maxTimes[car])/1000;a_60_90[car]+="<BR><I><FONT color='#333333'>Start in gear "+bestStartGear+"</FONT></I>";for(var i in bestShiftRpms){var temp=parseInt(i)+1;a_60_90[car]+="<BR><I><FONT color='#333333'>Shift gear "+i+" to "+temp+" @ "+Math.round(bestShiftRpms[i])+" RPM</FONT></I>";}};if((minSpeed[car]>60)||(topSpeed[car]<120)){a_60_120="-";}else{findOptGears(car,60,120);a_60_120[car]=parseFloat(maxTimes[car])/1000;a_60_120[car]+="<BR><I><FONT color='#333333'>Start in gear "+bestStartGear+"</FONT></I>";for(var i in bestShiftRpms){var temp=parseInt(i)+1;a_60_120[car]+="<BR><I><FONT color='#333333'>Shift gear "+i+" to "+temp+" @ "+Math.round(bestShiftRpms[i])+" RPM</FONT></I>";}}}}function drawPerformanceTable(id){content="";content+="<TABLE WIDTH='100%' CELLPADDING='3' CELLSPACING='1' BORDER='1' RULES='VSIDES' FRAME='BOX'>";content+="<TR><TH></TH>";for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}content+="<TH>"+carNames[car]+"</TH>";}content+="<TR><TH align='left'>Peak Power (HP)</TH>";for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}content+="<TD align='right'>"+peakPower[car]+" @ "+peakPowerRpm[car]+" RPM</TD>";}content+="<TR><TH align='left'>Peak Torque (ft-lbf)</TH>";for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}content+="<TD align='right'>"+peakTorque[car]+" @ "+peakTorqueRpm[car]+" RPM</TD>";}content+="<TR><TH align='left'>Top Speed (mph)</TH>";for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}content+="<TD align='right'>"+topSpeed[car]+"</TD>";}content+="<TR><TH align='left'>30-60 time (s)</TH>";for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}content+="<TD align='right'>"+a_30_60[car]+"</TD>";}content+="<TR><TH align='left'>30-90 time (s)</TH>";for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}content+="<TD align='right'>"+a_30_90[car]+"</TD>";}content+="<TR><TH align='left'>30-120 time (s)</TH>";for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}content+="<TD align='right'>"+a_30_120[car]+"</TD>";}content+="<TR><TH align='left'>60-90 time (s)</TH>";for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}content+="<TD align='right'>"+a_60_90[car]+"</TD>";}content+="<TR><TH align='left'>60-120 time (s)</TH>";for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}content+="<TD align='right'>"+a_60_120[car]+"</TD>";}content+="<TR><TH align='left'>Cruising RPM<BR>at 80mph</TH>";for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}content+="<TD align='right'>"+Math.round(cruisingRpm[car])+"</TD>";}content+="</TABLE>";document.getElementById(id).innerHTML=content;}function drawPerformanceCharts(id){content="";content+="<TABLE>";content+="<TR><TD><DIV id='selected_chart'></DIV></TD>";content+="<TD><TABLE><TR><TD align='left'>Select Chart<TR><TD>";content+="<SELECT onChange='chartSelect(this.selectedIndex)'>";content+="<OPTION SELECTED>HP and Torque</OPTION>";content+="<OPTION>Speed vs Time</OPTION>";content+="<OPTION>Distance vs Time</OPTION>";content+="<OPTION>Acceleration vs Time</OPTION>";if(gap.length>0){content+="<OPTION>Gap vs Time</OPTION>";}content+="</SELECT></TABLE></TD></TR>";content+="</TABLE>";document.getElementById(id).innerHTML=content;var chartData=powerTorqueComparison();drawBlankChart("selected_chart",chartData);}function drawBlankChart(id,data){var chart=new FusionCharts("FusionCharts/DragLine.swf","pChartId","675","600","0","1");chart.setDataXML(data);chart.render(id);}function chartSelect(ind){var data;if(ind==0){data=powerTorqueComparison();}else if(ind==1){data=speedTimeComparison();}else if(ind==2){data=distanceTimeComparison();}else if(ind==3){data=accelerationTimeComparison();}else if(ind==4&&gap.length>0){data=gapTimeComparison();}var t=getChartFromId("pChartId");t.setDataXML(data);}function powerTorqueComparison(){var labelDisplay="NONE";var labelStep=5;var lb=20000;var ub=0;for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}if(findLowerThousand(minRpm[car])<lb){lb=findLowerThousand(minRpm[car]);}if(findUpperThousand(maxRpm[car])>ub){ub=findUpperThousand(maxRpm[car]);}var tmp=parseInt(1000/parseInt(stepRpm[car]));var numVDivLines=findNumVLines(lb,ub);}// Generate XML data
var data="<chart animation='1' palette='1' chartTopMargin='30' labelDisplay='NONE' labelStep='"+labelStep+"' caption='Torque and Power' subcaption='Solid and dashed lines indicate torque and power respectively.' showvalues='0' rotatevalues='0' xAxisName='RPM' yAxisName='Torque (ft-lbf) or Power (HP)' showformbtn='0' showrestorebtn='0' canvasborderthickness='2' canvasPadding='0' dragBorderThickness='3' donotsnap='1' showlegend='1' decimals='0' yAxisValueDecimals='3000' lineThickness='2' connectNullData='1' numVDivLines='"+numVDivLines+"' vDivLineIsDashed='1'>";data+="<categories> ";for(var i=parseInt(lb);i<=parseInt(ub);i=i+100){data+="<category name='"+i+"' />";}data+="</categories> ";for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}var carPlusOne=car+1;data+="<dataset id='T"+car+"' seriesName='"+carNames[car]+"' color='"+lineColors[car%4]+"'>";for(var i=parseInt(lb);i<=parseInt(ub);i=i+100){if(isVisible(i,parseInt(minRpm[car]),parseInt(maxRpm[car]),parseInt(stepRpm[car]))){if(i==peakTorqueRpm[car]){data+="<set id='T"+i+"' label='"+i+"' value='"+torques[car][i]+"' allowDrag='0' anchorBorderColor='"+lineColors[car%4]+"' showValue='1' anchorRadius='4' anchorBorderThickness='3' toolText='"+carNames[car]+" peak torque ("+torques[car][i]+" ft-lbf @ "+i+" RPM)'/> ";}else{data+="<set id='T"+i+"' label='"+i+"' value='"+torques[car][i]+"' allowDrag='0' anchorBorderColor='"+lineColors[car%4]+"'/> ";}}else{data+="<set id='T"+i+"' label='"+i+"'/>";}}data+="</dataset>";data+="<dataset id='P"+car+"' seriesName='Car "+carPlusOne+"' includeInLegend='0' color='"+lineColors[car%4]+"' anchorBorderColor='"+lineColors[car%4]+"' dashed='1'>";for(var i=parseInt(lb);i<=parseInt(ub);i=i+100){if(isVisible(i,parseInt(minRpm[car]),parseInt(maxRpm[car]),parseInt(stepRpm[car]))){if(i==peakPowerRpm[car]){data+="<set id='P"+i+"' label='"+i+"' value='"+powers[car][i]+"' allowDrag='0' anchorBorderColor='"+lineColors[car%4]+"' showValue='1' anchorRadius='4' anchorBorderThickness='3' toolText='Car "+carPlusOne+" peak power ("+powers[car][i]+" HP @ "+i+" RPM)'/> ";}else{data+="<set id='P"+i+"' label='"+i+"' value='"+powers[car][i]+"' allowDrag='0' />";}}else{data+="<set id='P"+i+"' label='"+i+"'/>";}}data+="</dataset>";}data+="</chart>";return data;}function calculateGap(){var max=-1;gap=new Array();gapLabel=new Array();if(countCars()==1){return;}// max time 
for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}if(max==-1||max>maxTimes[car]){max=maxTimes[car];}}var counter=0;for(var cari=0;cari<numCars;cari++){if(!showCar[cari]){continue;}for(var carj=cari+1;carj<numCars;carj++){if(!showCar[carj]){continue;}if(distanceAtInstants[cari][max]>distanceAtInstants[carj][max]){gapLabel[counter]=carNames[cari]+" beats "+carNames[carj];gap[counter]=new Array();for(var t=0;t<=max;t=t+timeStep){gap[counter][t]=(distanceAtInstants[cari][t]-distanceAtInstants[carj][t])/15;}}else{gapLabel[counter]=carNames[carj]+" beats "+carNames[cari];gap[counter]=new Array();for(var t=0;t<=max;t=t+timeStep){gap[counter][t]=(distanceAtInstants[carj][t]-distanceAtInstants[cari][t])/15;}};counter++;}}}function speedTimeCalculations(){var lb=commonMinSpeed;var ub=commonMaxSpeed-10;if(lb<20){lb=20;}else if(lb<30){lb=30;}if(ub>120){ub=120;}findSpeedAtInstants(lb,ub);}function speedTimeComparison(){var max=maxTime+timeStep;
var data="<chart animation='0' palette='1' chartTopMargin='30' labelDisplay='NONE' labelStep='20' caption='Speed vs Time' showvalues='0' rotatevalues='0' xAxisName='Time (s)' yAxisName='Speed (mph)' yAxisMaxValue='150' showformbtn='0' showrestorebtn='0' canvasborderthickness='2' canvasPadding='0' dragBorderThickness='3' donotsnap='1' showlegend='1' decimals='2' yAxisValueDecimals='3000' lineThickness='2' connectNullData='1' vDivLineIsDashed='1' anchorRadius='1'>";data+="<categories> ";for(var i=0;i<=max;i=i+timeStep){var time=i/1000;data+="<category name='"+time+"' />";}data+="</categories> ";for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}var carPlusOne=car+1;data+="<dataset id='S"+car+"' seriesName='"+carNames[car]+"' color='"+lineColors[car%4]+"'>";var gear=optGears[car][0];for(var i=0;i<=max;i=i+timeStep){var time=i/1000;if(typeof(speedAtInstants[car][i])=="undefined"){data+="<set id='S"+i+"' label='"+time+"' allowDrag='0' anchorBorderColor='"+lineColors[car%4]+"'/> ";}else{if((typeof(optGears[car][i])!="undefined")&&(gear!=optGears[car][i])){data+="<set id='S"+i+"' label='"+time+"' value='"+speedAtInstants[car][i]+"' allowDrag='0' anchorBorderColor='"+lineColors[car%4]+"' showValue='1' anchorRadius='2' toolText='"+carNames[car]+" gear shift from "+gear+" to "+optGears[car][i]+" @ "+Math.round(bestShiftRpmsForAllCars[car][gear])+" RPM'/> ";gear=optGears[car][i];}else{data+="<set id='S"+i+"' label='"+time+"' value='"+speedAtInstants[car][i]+"' allowDrag='0' anchorRadius='1' anchorBorderColor='"+lineColors[car%4]+"'/> ";}}}data+="</dataset>";}data+="</chart>";return data;}function accelerationTimeComparison(){var max=maxTime+timeStep;
data="<chart animation='0' palette='1' chartTopMargin='30' labelDisplay='NONE' labelStep='20' caption='Acceleration vs Time' showvalues='0' rotatevalues='0' xAxisName='Time (s)' yAxisName='Acceleration (G)' showformbtn='0' showrestorebtn='0' canvasborderthickness='2' canvasPadding='0' dragBorderThickness='3' donotsnap='1' showlegend='1' decimals='3' yAxisValueDecimals='3000' lineThickness='2' connectNullData='1' vDivLineIsDashed='1' anchorRadius='1'>";data+="<categories> ";for(var i=0;i<max;i=i+timeStep){var time=i/1000;data+="<category name='"+time+"' />";}data+="</categories> ";for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}var carPlusOne=car+1;data+="<dataset id='A"+car+"' seriesName='"+carNames[car]+"' color='"+lineColors[car%4]+"'>";var gear=optGears[car][0];for(var i=0;i<max;i=i+timeStep){var time=i/1000;if(typeof(accelerationAtInstants[car][i])=="undefined"){data+="<set id='A"+i+"' label='"+time+"' allowDrag='0' anchorBorderColor='"+lineColors[car%4]+"'/> ";}else{if((typeof(optGears[car][i])!="undefined")&&(gear!=optGears[car][i])){data+="<set id='S"+i+"' label='"+time+"' value='"+accelerationAtInstants[car][i]+"' allowDrag='0' anchorBorderColor='"+lineColors[car%4]+"' showValue='1' anchorRadius='2' toolText='"+carNames[car]+" gear shift from "+gear+" to "+optGears[car][i]+" @ "+Math.round(bestShiftRpmsForAllCars[car][gear])+" RPM'/> ";gear=optGears[car][i];}else{data+="<set id='S"+i+"' label='"+time+"' value='"+accelerationAtInstants[car][i]+"' allowDrag='0' anchorRadius='1' anchorBorderColor='"+lineColors[car%4]+"'/> ";}}}data+="</dataset>";}data+="</chart>";return data;}function gapTimeComparison(){
var data="<chart animation='0' palette='1' chartTopMargin='30' labelDisplay='NONE' labelStep='20' caption='Gap vs Time' subcaption='(All cars start at 20mph, 1 car length is 15ft)' showvalues='0' rotatevalues='0' xAxisName='Time (s)' yAxisName='Gap (car lengths)' showformbtn='0' showrestorebtn='0' canvasborderthickness='2' canvasPadding='0' dragBorderThickness='3' donotsnap='1' showlegend='1' decimals='2' yAxisValueDecimals='3000' lineThickness='2' connectNullData='1' vDivLineIsDashed='1' anchorRadius='1'>";var temp=gap[0];var max=temp.length-1;
data+="<categories> ";for(var i=0;i<=max;i=i+timeStep){var time=i/1000;data+="<category name='"+time+"' />";}data+="</categories> ";for(var plot=0;plot<gapLabel.length;plot++){data+="<dataset id='G"+plot+"' seriesName='"+gapLabel[plot]+"'>";for(var i=0;i<=max;i=i+timeStep){var time=i/1000;data+="<set id='G"+i+"' label='"+time+"' value='"+gap[plot][i]+"' allowDrag='0' anchorRadius='1' /> ";}data+="</dataset>";}data+="</chart>";return data;}function distanceTimeComparison(){var max=maxTime+timeStep;
var data="<chart animation='0' palette='1' chartTopMargin='30' labelDisplay='NONE' labelStep='20' caption='Distance vs Time' subcaption='(All cars start at 20mph)' showvalues='0' rotatevalues='0' xAxisName='Time (s)' yAxisName='Distance (feet)' yAxisMaxValue='150' showformbtn='0' showrestorebtn='0' canvasborderthickness='2' canvasPadding='0' dragBorderThickness='3' donotsnap='1' showlegend='1' decimals='2' yAxisValueDecimals='3000' lineThickness='2' connectNullData='1' vDivLineIsDashed='1' anchorRadius='1'>";data+="<categories> ";for(var i=0;i<=max;i=i+timeStep){var time=i/1000;data+="<category name='"+time+"' />";}data+="</categories> ";for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}var carPlusOne=car+1;data+="<dataset id='S"+car+"' seriesName='"+carNames[car]+"' color='"+lineColors[car%4]+"'>";var gear=optGears[car][0];for(var i=0;i<=max;i=i+timeStep){var time=i/1000;if(typeof(distanceAtInstants[car][i])=="undefined"){data+="<set id='S"+i+"' label='"+time+"' allowDrag='0' anchorBorderColor='"+lineColors[car%4]+"'/> ";}else{if((typeof(optGears[car][i])!="undefined")&&(gear!=optGears[car][i])){data+="<set id='S"+i+"' label='"+time+"' value='"+distanceAtInstants[car][i]+"' allowDrag='0' anchorBorderColor='"+lineColors[car%4]+"' showValue='1' anchorRadius='2' toolText='"+carNames[car]+" gear shift from "+gear+" to "+optGears[car][i]+" @ "+Math.round(bestShiftRpmsForAllCars[car][gear])+" RPM'/> ";gear=optGears[car][i];}else{data+="<set id='S"+i+"' label='"+time+"' value='"+distanceAtInstants[car][i]+"' allowDrag='0' anchorRadius='1' anchorBorderColor='"+lineColors[car%4]+"'/> ";}}}data+="</dataset>";}data+="</chart>";return data;}function getTorque(rpm,gear,car){if(rpm<minRpm[car]||rpm>maxRpm[car]){alert("fatal error: rpm out of range");}var a;var b;for(var r=parseInt(minRpm[car]);r<=parseInt(maxRpm[car]);r=r+parseInt(stepRpm[car])){if(r<=rpm){a=r;}else{b=r;break;}}var val=torques[car][a]+(rpm-a)*(torques[car][b]-torques[car][a])/(b-a);var tireCircum=getTireCircum(car);var torque=(1.9694/tireCircum)*differentials[car]*gearRatios[car][gear]*val;
return torque;}function getSpeedAtRpm(rpm,gear,car){var tireCircum=getTireCircum(car);var gearRatio=parseFloat(gearRatios[car][gear]);var diffRatio=parseFloat(differentials[car]);var tireRpm=parseFloat(rpm)/(gearRatio*diffRatio);return(tireRpm*tireCircum*60)/1609.344;}function getRpmAtSpeed(speed,gear,car){
var tireCircum=getTireCircum(car);var rpmAtTire=(parseFloat(speed)*1609.344/60)/tireCircum;var gearRatio=parseFloat(gearRatios[car][gear]);var diffRatio=parseFloat(differentials[car]);var ret=rpmAtTire*gearRatio*diffRatio;
return ret;}function getTireCircum(car){
var diaInInches=0.000787402*parseInt(tireWidth[car])*parseInt(tireRatio[car])+parseFloat(tireIntDia[car]);return(0.0254*diaInInches*3.1416);}function findMinSpeed(car){return getSpeedAtRpm(minRpm[car],1,car);}function findMaxSpeed(car){var rpmLimitedSpeed=parseInt(getSpeedAtRpm(maxRpm[car],numGears[car],car));var minSpeed=parseInt(findMinSpeed(car))+1;for(var speed=rpmLimitedSpeed;speed>=minSpeed;speed--){for(var gear=numGears[car];gear>=1;gear--){var rpm=getRpmAtSpeed(speed,gear,car);
if(rpm>parseFloat(maxRpm[car])){break;}var torque=getTorque(rpm,gear,car);var dragForce=findAirDragAtSpeed(speed,car);
if(torque>dragForce){return speed;}}}}function findOptGears(car,minSpeed,maxSpeed){maxTimes[car]=0;var optGear=new Array();var bestOptGear;var shiftRpms;var numTicks=parseFloat(shiftingTime[car])/timeStep;var minGearAtMinSpeed;var maxGearAtMinSpeed;var minGearAtMaxSpeed;var maxGearAtMaxSpeed;for(var g=numGears[car];g>=1;g--){if(getRpmAtSpeed(minSpeed,g,car)<maxRpm[car]){minGearAtMinSpeed=g;}if(getRpmAtSpeed(maxSpeed,g,car)<maxRpm[car]){minGearAtMaxSpeed=g;}}for(var g=1;g<=numGears[car];g++){if(getRpmAtSpeed(minSpeed,g,car)>minRpm[car]){maxGearAtMinSpeed=g;}if(getRpmAtSpeed(maxSpeed,g,car)>minRpm[car]){maxGearAtMaxSpeed=g;}}var totalTime=-1;for(var minGear=minGearAtMinSpeed;minGear<=maxGearAtMinSpeed;minGear++){for(var maxGear=minGearAtMaxSpeed;maxGear<=maxGearAtMaxSpeed;maxGear++){
if(maxGear!=maxGearAtMaxSpeed){continue;}if(maxGear<minGear){continue;}shiftRpms=new Array();var time=0;var speed=minSpeed;var gear=minGear;var counter=0;while(true){var torque=0;var newGear;
for(var g=gear;(g<=maxGear)&&(g<=(gear+1));g++){var rpm=getRpmAtSpeed(speed,g,car);if(rpm<minRpm[car]||rpm>maxRpm[car]){continue;}var temp=getTorque(rpm,g,car);if(torque<temp){torque=temp;newGear=g;}}if(newGear!=gear){var t=getRpmAtSpeed(speed,gear,car);if(t>maxRpm[car]){shiftRpms[gear]=maxRpm[car];}else{shiftRpms[gear]=t;};for(var tick=1;tick<=numTicks;tick++){optGear[time]=newGear;time=time+timeStep;var force=-findAirDragAtSpeed(speed,car);var speedInc=accFactor*force/parseFloat(totalWeight[car])*timeStep/1000;speed=speed+speedInc;}gear=newGear;}optGear[time]=gear;var rpm=getRpmAtSpeed(speed,gear,car);var force=torque-findAirDragAtSpeed(speed,car);var speedInc=accFactor*force/parseFloat(totalWeight[car])*timeStep/1000;
speed=speed+speedInc;time=time+timeStep;if(speed>=maxSpeed){break;}}var tempTotalTime=time;if((totalTime==-1)||(tempTotalTime<totalTime)){totalTime=tempTotalTime;bestOptGear=optGear;bestShiftRpms=shiftRpms;bestStartGear=minGear;optGear=new Array();maxTimes[car]=totalTime;}
}}optGears[car]=bestOptGear;}function findSpeedAtInstants(minSpeed,maxSpeed){maxTime=0;for(var car=0;car<numCars;car++){if(!showCar[car]){continue;}var numTicks=parseFloat(shiftingTime[car])/timeStep;findOptGears(car,minSpeed,maxSpeed);speedAtInstants[car]=new Array();bestShiftRpmsForAllCars[car]=bestShiftRpms;distanceAtInstants[car]=new Array();accelerationAtInstants[car]=new Array();speedAtInstants[car][0]=minSpeed;distanceAtInstants[car][0]=0;var gear=optGears[car][0];for(var t=0;t<maxTimes[car];t=t+timeStep){if(gear!=optGears[car][t]){for(var tick=1;tick<=numTicks;tick++){var torque=0;var force=torque-findAirDragAtSpeed(speedAtInstants[car][t],car);var speedInc=accFactor*force/parseFloat(totalWeight[car])*timeStep/1000;speedAtInstants[car][t+tick*timeStep]=speedAtInstants[car][t+(tick-1)*timeStep]+speedInc;distanceAtInstants[car][t+tick*timeStep]=distanceAtInstants[car][t+(tick-1)*timeStep]+5.28*speedAtInstants[car][t+(tick-1)*timeStep]*timeStep/(3600);accelerationAtInstants[car][t+(tick-1)*timeStep]=accelerationFraudFactor*accFactor*force/parseFloat(totalWeight[car])*1609/(3600*9.86);}gear=optGears[car][t];t=t+numTicks*timeStep;}var rpm=getRpmAtSpeed(speedAtInstants[car][t],optGears[car][t],car);var torque=getTorque(rpm,optGears[car][t],car);var force=torque-findAirDragAtSpeed(speedAtInstants[car][t],car);var speedInc=accFactor*force/parseFloat(totalWeight[car])*timeStep/1000;accelerationAtInstants[car][t]=accelerationFraudFactor*accFactor*force/parseFloat(totalWeight[car])*1609/(3600*9.86);
var newInd=t+timeStep;distanceAtInstants[car][newInd]=distanceAtInstants[car][t]+5.28*speedAtInstants[car][t]*timeStep/(3600);speedAtInstants[car][newInd]=speedAtInstants[car][t]+speedInc;}if(maxTime<maxTimes[car]){maxTime=maxTimes[car];}}}function findAirDragAtSpeed(speed,car){var t=parseFloat(speed);return(airDragFactor[car]*t*t);}
