<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN"   "http://www.web3d.org/specifications/x3d-3.0.dtd">
<X3D profile='Immersiveversion='3.0xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation=' http://www.web3d.org/specifications/x3d-3.0.xsd '>
<head>
<meta name='titlecontent='ProjectileInterpolatorPrototype.x3d'/>
<meta name='descriptioncontent='A proto which simulates x-y plane projectile motion.'/>
<meta name='creatorcontent='Ozan APAYDIN'/>
<meta name='createdcontent='10 December 2001'/>
<meta name='modifiedcontent='16 August 2008'/>
<meta name='identifiercontent=' http://www.web3d.org/x3d/content/examples/Basic/StudentProjects/ProjectileInterpolatorPrototype.x3d '/>
<meta name='generatorcontent='X3D-Edit 3.2, https://savage.nps.edu/X3D-Edit'/>
<meta name='licensecontent='../license.html'/>
</head>
<!--

Index for ProtoDeclare definition: ProjectileInterpolator
Index for DEF node: ProjectileMotionTrackerScript
-->
<Scene>
<ProtoDeclare name='ProjectileInterpolatorappinfo='This prototype is a Projectile Motion Interpolator. It takes Inputs : Initial Velocity and Angle then calculates trajectory of the projectile on x-y plane according to given dt time and B_m. It outputs value_changed values(SFVec3f).'>
<ProtoInterface>
<field name='Vitype='SFFloataccessType='initializeOnly'
 appinfo='Initial Velocity value of the object.'/>
<field name='thetatype='SFFloataccessType='initializeOnly'
 appinfo='Launch Angle. The angle between horizantal and launch direction'/>
<field name='B_mtype='SFFloatvalue='0.00004accessType='initializeOnly'
 appinfo='Proportional to drag force = B2/m'/>
<field name='dttype='SFFloatvalue='0.1accessType='initializeOnly'
 appinfo='Time step.'/>
<field name='fractiontype='SFFloataccessType='initializeOnly'
 appinfo='SFFloat Values ranging [0..1].'/>
<field name='set_fractiontype='SFFloataccessType='inputOnly'
 appinfo='The set_fraction eventIn receives an SFFloat event and causes the interpolator function to evaluate resulting in a value_changed eventOut with the same timestamp as the set_fraction event.'/>
<field name='set_thetatype='SFFloataccessType='inputOnly'
 appinfo='Sets theta to the value of eventIn.'/>
<field name='set_Vitype='SFFloataccessType='inputOnly'
 appinfo='Sets Vi to the value of eventIn.'/>
<field name='value_changedtype='SFVec3faccessType='outputOnly'
 appinfo='The interpolator function eventOut results as Vector3Float.'/>
</ProtoInterface>
<ProtoBody>
<Script DEF='ProjectileMotionTrackerScript'>
<field name='Vitype='SFFloataccessType='initializeOnly'/>
<field name='thetatype='SFFloataccessType='initializeOnly'/>
<field name='B_mtype='SFFloataccessType='initializeOnly'/>
<field name='dttype='SFFloataccessType='initializeOnly'/>
<field name='fractiontype='SFFloataccessType='initializeOnly'
 appinfo='In range [01]'/>
<field name='set_fractiontype='SFFloataccessType='inputOnly'/>
<field name='set_thetatype='SFFloataccessType='inputOnly'/>
<field name='set_Vitype='SFFloataccessType='inputOnly'/>
<field name='value_changedtype='SFVec3faccessType='outputOnly'/>
<IS>
<connect nodeField='ViprotoField='Vi'/>
<connect nodeField='thetaprotoField='theta'/>
<connect nodeField='B_mprotoField='B_m'/>
<connect nodeField='dtprotoField='dt'/>
<connect nodeField='fractionprotoField='fraction'/>
<connect nodeField='set_fractionprotoField='set_fraction'/>
<connect nodeField='set_thetaprotoField='set_theta'/>
<connect nodeField='set_ViprotoField='set_Vi'/>
<connect nodeField='value_changedprotoField='value_changed'/>
</IS>
<![CDATA[
          ecmascript:
var x;
var y;
var Vx;
var Vy;
var B_m;
var dt;
var blocksize;
var Vi;
var theta;

var key;
var keyValue;
var previousFraction;
var previousFractionIndex;
var blockSize;
var outputArray;

function tracePrint (outputString)
{
	var traceEnabled = true;
	if (traceEnabled) Browser.print ('[WaypointInterpolator]' + outputString);
}
function forcePrint (outputString)
{
	Browser.print ('[WaypointInterpolator]' + outputString);
}



function initialize() {
   key = new Array();
   keyValue = new MFVec3f();
   x = new Array();
   y = new Array();
   calculateTrajectory();

   previousFractionIndex = -1;
	previousFraction = 0;
	// check key array ranges [0..1] and is monotonically increasing
	// check that size of keyValue array is integer multiple of size of key array
	tracePrint ('key            =' + key);
	tracePrint ('key.length= ' + key.length);
	tracePrint ('keyValue=   ' + keyValue);
	tracePrint ('keyValue.length=' + keyValue.length);
	blockSize =  3; //keyValue.length/key.length;
	tracePrint ('blockSize=' + blockSize);
	if (blockSize != Math.round(blockSize))
	{
	  forcePrint ('*** warning:  blockSize not an integer multiple. check sizes of key and keyValue');
	}
	if (key[0] != 0)
	{
	  forcePrint ('*** warning:  key[0] != 0');
	}
	if (key[key.length-1] != 1)
	{
	  forcePrint ('*** warning:  key[' + (key.length - 1) + '] != 1, reset from' + key[key.length-1] + ' to 1');
	  key[key.length-1] = 1;
	}
	for (index = 0; index < blockSize; index++)
	{
		if ((key[index] < 0) || (key[index] > 1))
		{
		   forcePrint ('*** warning:  key[' + index + '] =' + key[index] + ', out of range [0..1]');
		}
	}
	// instantiate default array, later computations just update it
	outputArray = new SFVec3f();
	outputArray = keyValue[0];
	tracePrint ('initial outputArray=' + outputArray);

}

function set_fraction (inputFloat, timestamp) {
	fraction = inputFloat;
	tracePrint ('previousFractionIndex=' + previousFractionIndex
		 + ', fraction=' + fraction + ', previousFraction=' + previousFraction);

	if (fraction < 0)
	{
		tracePrint ('*** illegal fraction' + fraction + ' set to 0');
		fraction = 0;
		previousFractionIndex = 0; // first
	}
	else if (fraction > 1)
	{
		forcePrint ('*** illegal fraction' + fraction + ' set to 1');
		fraction = 1;
		previousFractionIndex = blockSize - 1; // last
	}
	else if (previousFractionIndex == -1)
	{
		previousFractionIndex = 0; // first
		tracePrint ('previousFractionIndex initialized for first event');
	}
	else if ((fraction >= previousFraction) && (fraction >= key[previousFractionIndex+1]))
	{
		previousFractionIndex++;
	}
	else if (fraction < previousFraction) // regress, or loop repeat without reaching one
	{

		previousFractionIndex = 0;
		while ((fraction >= key[previousFractionIndex+1]) && (previousFractionIndex < blockSize))
		{
			previousFractionIndex++;
		}
		tracePrint ('reset/reincrement previousFractionIndex to' + previousFractionIndex);
	}

	if (fraction == 1) // use final block
	{
		tracePrint ('(fraction == 1)');


        	outputArray = keyValue[(keyValue.length -1)];

		previousFractionIndex = -1; // setup for restart
		tracePrint ('finished final fraction==1 block');
	}
	// when fraction matches index, calculate value_changed from corresponding keyValue array
	else if (fraction == key[previousFractionIndex])
	{
		tracePrint ('(fraction == key[previousFractionIndex])');


		// update outputArray - need to interpolate next
		outputArray = keyValue[previousFractionIndex];

	}
        else {

              delta = key[previousFractionIndex + 1] -  key[previousFractionIndex];
              differ = fraction - key[previousFractionIndex];
              percentDiffer = differ / delta;

              valueDelta = new SFVec3f();
              for(index = 0; index < blockSize; index++) {
                 valueDelta[index] =  keyValue[(previousFractionIndex + 1)][index] - keyValue[previousFractionIndex][index];
                 outputArray[index]  = keyValue[previousFractionIndex][index] + valueDelta[index] * percentDiffer;
		 Browser.print ('valueDelta' + valueDelta[index]);
                 Browser.print ('perDiffer' + percentDiffer);
              }

        }

	value_changed = outputArray;
	previousFraction = fraction;
	tracePrint ('value_changed=' + value_changed);

}


function set_Vi(initialVelocity, timeStamp) {
   Vi = initialVelocity;
   initialize(timeStamp);
}


function set_theta(angle, timeStamp) {
   theta = angle;
   initialize(timeStamp);
}


function calculateTrajectory() {

   x[0] = 0;
   y[0] = 0;

   var timeKeys = new Array();
   timeKeys[0] = 0.0;

   //convert degree to radian
   angle = Math.PI * theta / 180;

   Vx = Vi * Math.cos(angle);
   Vy = Vi * Math.sin(angle);

   var i = 0;

   do {
      i = i + 1;
      timeKeys[i] = timeKeys[i - 1] + dt;
      Browser.print ('timeKeys' + timeKeys[i]);
      x[i] = x[i - 1] + Vx * dt;
      y[i] = y[i - 1] + Vy * dt;


      f = B_m * Math.sqrt(Vx * Vx + Vy * Vy) * Math.exp(-y[i] / 0.0001);

      Vy = Vy - 9.8 * dt - f * Vy * dt;
      Vx = Vx - f * Vx * dt;
      Browser.print ('Vy' + Vy);
   }while(y[i] > 0);
   Browser.print ('Im here' + x.length);

   //interpolate to find landing point
   var a = -y[i] / y[i-1];
   x[i] = (x[i] + a * x[i-1]) / (1+a);
   y[i] = 0;

   //copy x, y values to keyValues
   copyToKeyValues();
   //finding keys
   for(j = 0; j < timeKeys.length; j++) {
      key[j] = timeKeys[j] / timeKeys[timeKeys.length - 1];
      Browser.print (' ' + key[j]);

   }

}

function copyToKeyValues() {
   for(i = 0; i < x.length; i++) {
     Browser.print ('x' + x[i]);
      keyValue[i][0] = x[i];
      keyValue[i][1] = y[i];
      keyValue[i][2] = 0;
   Browser.print ('keyValue' + i + ' ' + keyValue[i][0]);
   }

}
        
]]>
</Script>
</ProtoBody>
</ProtoDeclare>
<!-- ==================== -->
<Anchor description='ProjectileInterpolatorArenaparameter='target=_blank'
  url=' "ProjectileInterpolatorArena.wrl" "http://www.web3d.org/x3d/content/examples/Basic/StudentProjects/ProjectileInterpolatorArena.wrl" "ProjectileInterpolatorArena.x3d" "http://www.web3d.org/x3d/content/examples/Basic/StudentProjects/ProjectileInterpolatorArena.x3d" '>
<Shape>
<Text string='"ProjectileInterpolatorPrototype" "defines a prototype" "" "Click on this text to see" "ProjectileInterpolatorArena" " scene"solid='true'>
<FontStyle justify='"MIDDLE" "MIDDLE"size='0.7'/>
</Text>
<Appearance>
<Material diffuseColor='1 1 0.2'/>
</Appearance>
</Shape>
</Anchor>
<PositionInterpolator/>
</Scene>
</X3D>
<!--

Index for ProtoDeclare definition: ProjectileInterpolator
Index for DEF node: ProjectileMotionTrackerScript
-->

<!-- Tag color codes: <Node DEF='idName' attribute='value'/> <Prototype name='ProtoName'> <field name='fieldName'/> </Prototype> -->