<?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
-->
X3D Tooltips element index: Anchor, Appearance, connect, field, FontStyle, head, IS, Material, meta, PositionInterpolator, ProtoBody, ProtoDeclare, ProtoInterface, Scene, Script, Shape, Text, WorldInfo, X3D, accessType and type, XML data types, field types


<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 <!-- Index for DEF node: ProjectileMotionTrackerScript

Index for ProtoDeclare definition: ProjectileInterpolator
-->

Event Graph ROUTE Table with 0 ROUTE connections 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.
This Script has no direct access to other nodes. 


Anchor
description='ProjectileInterpolatorArena' 
User-interaction hint for 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. -->