<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN" "https://www.web3d.org/specifications/x3d-3.0.dtd">
<X3D profile='Immersive'  version='3.0 xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation =' https://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='20 October 2019'/>
<meta name='identifiercontent=' https://www.web3d.org/x3d/content/examples/Basic/StudentProjects/ProjectileInterpolatorPrototype.x3d '/>
<meta name='generatorcontent='X3D-Edit 3.3, https://savage.nps.edu/X3D-Edit'/>
<meta name='licensecontent=' ../license.html'/>
</head>
<!--

to top <!-- Event Graph ROUTE Table shows event connections -->
 
<!-- Index for DEF node: ProjectileMotionTrackerScript

Index for ProtoDeclare definition: ProjectileInterpolator
-->
<Scene>
<WorldInfo title='ProjectileInterpolatorPrototype.x3d'/>
<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.println ('[WaypointInterpolator]' + outputString);
}
function alwaysPrint (outputString)
{
	Browser.println ('[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))
	{
	  alwaysPrint ('*** warning:  blockSize not an integer multiple. check sizes of key and keyValue');
	}
	if (key[0] != 0)
	{
	  alwaysPrint ('*** warning:  key[0] != 0');
	}
	if (key[key.length-1] != 1)
	{
	  alwaysPrint ('*** 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))
		{
		   alwaysPrint ('*** 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)
	{
		alwaysPrint ('*** 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.println ('valueDelta' + valueDelta[index]);
                 Browser.println ('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.println ('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.println ('Vy' + Vy);
   }while(y[i] > 0);
   Browser.println ('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.println (' ' + key[j]);

   }

}

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

}

        
]]>
</Script>
</ProtoBody>
</ProtoDeclare>
<!-- ==================== -->
<Anchor description='ProjectileInterpolatorArenaparameter='"target=_blank"'
  url=' "ProjectileInterpolatorArena.wrl" "https://www.web3d.org/x3d/content/examples/Basic/StudentProjects/ProjectileInterpolatorArena.wrl" ProjectileInterpolatorArena.x3d"https://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"'>
<FontStyle justify='"MIDDLE" "MIDDLE"size='0.7'/>
</Text>
<Appearance>
<Material diffuseColor='1 1 0.2'/>
</Appearance>
</Shape>
</Anchor>
<PositionInterpolator/>
</Scene>
</X3D>
<!--

to top <!-- Event Graph ROUTE Table shows event connections -->
 
<!-- Index for DEF node: ProjectileMotionTrackerScript

Index for ProtoDeclare definition: ProjectileInterpolator
-->

Event Graph ROUTE Table with 0 ROUTE total, showing X3D event-model relationships for this scene.

Each row shows an event cascade that may occur during a single timestamp interval between frame renderings, as part of the X3D execution model.

ProjectileMotionTrackerScript
Script
No ROUTE connection found for output from this node.
 


-->

<!-- Online at
https://www.web3d.org/x3d/content/examples/Basic/StudentProjects/ProjectileInterpolatorPrototypeIndex.html -->
<!-- Version control at
https://sourceforge.net/p/x3d/code/HEAD/tree/www.web3d.org/x3d/content/examples/Basic/StudentProjects/ProjectileInterpolatorPrototype.x3d -->

<!-- Color legend: X3D terminology <X3dNode DEF='idName' field='value'/> matches XML terminology <XmlElement DEF='idName' attribute='value'/>
(Light-blue background: event-based behavior node or statement) (Grey background inside box: inserted documentation) (Magenta background: X3D Extensibility)
    <ProtoDeclare name='ProtoName'> <field name='fieldName'/> </ProtoDeclare> -->

to top <!-- For additional help information about X3D scenes, please see X3D Tooltips, X3D Resources, and X3D Scene Authoring Hints. -->