X3D Model Documentation: IntegerSequencerPrototype.x3d

  1  <?xml version="1.0" encoding="UTF-8"?>
  2 
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN" "https://www.web3d.org/specifications/x3d-3.0.dtd">
  3  <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'>
  4       <head>
  5            <meta name='titlecontent='IntegerSequencerPrototype.x3d'/>
  6            <meta name='descriptioncontent='This proto, modeled after a ScalarInterpolator, generates an array of integer values based on the input fraction and keys.'/>
  7            <meta name=' warning content=' MFInt32 keyValue accessType is listed as initializeOnly/field, since inputOutput cannot be translated to exposedField in VRML97 scripting. '/>
  8            <meta name='creatorcontent='Don Brutzman, Estuko Lippi, Jeff Weekley, Jane Wu, Matthew Braun'/>
  9            <meta name='createdcontent='20 August 2001'/>
 10            <meta name='modifiedcontent='21 January 2020'/>
 11            <meta name='referencecontent='https://www.web3d.org/technicalinfo/specifications/vrml97/part1/nodesRef.html#ScalarInterpolator'/>
 12            <meta name='subjectcontent='integer sequencer'/>
 13            <meta name='identifiercontent='https://www.web3d.org/x3d/content/examples/Basic/development/IntegerSequencerPrototype.x3d'/>
 14            <meta name='generatorcontent='X3D-Edit 3.3, https://savage.nps.edu/X3D-Edit'/>
 15            <meta name='licensecontent='../license.html'/>
 16       </head>
<!--

<!--
Event Graph ROUTE Table shows event connections.
-->

<!-- to top Index for DEF nodes: KeyHolder, SequencerScript

Index for ProtoDeclare definition: IntegerSequencer
-->
 17       <Scene>
 18            <WorldInfo title='IntegerSequencerPrototype.x3d'/>
 19            <ProtoDeclare name='IntegerSequencer'>
 20                 <ProtoInterface>
 21                      <field name='set_fractiontype='SFFloataccessType='inputOnly'
                     appinfo='Regular interpolator-style input, range [0..1]'/>
 22                      <field name='set_keytype='MFFloataccessType='inputOnly'
                     appinfo='Array sequentially increasing typically [0..1]. Must have the same number of keys as keyValues.'/>
 23                      <field name='keytype='MFFloataccessType='inputOutput'
                     appinfo='Array sequentially increasing typically [0..1]. Must have the same number of keys as keyValues.'/>
 24                      <field name='key_changedtype='MFFloataccessType='outputOnly'
                     appinfo='Array sequentially increasing typically [0..1]. Must have the same number of keys as keyValues.'/>
 25                      <field name='set_keyValuetype='MFInt32accessType='inputOnly'
                     appinfo='Array of integer values. Must have the same number of keys as keyValues.'/>
 26                      <field name='keyValuetype='MFInt32accessType='initializeOnly'
                     appinfo='Array of integer values. Must have the same number of keys as keyValues.'/>
 27                      <field name='keyValue_changedtype='MFInt32accessType='outputOnly'
                     appinfo='Array of integer values. Must have the same number of keys as keyValues.'/>
 28                      <field name='value_changedtype='SFInt32accessType='outputOnly'
                     appinfo='Regular interpolator-style input'/>
 29                      <field name='previoustype='SFBoolaccessType='inputOnly'
                     appinfo='Utility method'/>
 30                      <field name='nexttype='SFBoolaccessType='inputOnly'
                     appinfo='Utility method'/>
 31                 </ProtoInterface>
 32                 <ProtoBody>
 33                      <Group>
 34                           <Switch whichChoice='-1'>
 35 
                              <!-- ScalarInterpolator KeyHolder is a DEF node that has 1 USE node: USE_1 -->
                              <ScalarInterpolator DEF='KeyHolder'>
 36                                     <IS>
 37                                          <connect nodeField='keyprotoField='key'/>
 38                                     </IS>
 39                                </ScalarInterpolator>
 40                           </Switch>
 41                           <Script DEF='SequencerScriptdirectOutput='true'>
 42                                <!-- Regular interpolator-style input -->
 43                                <field name='set_fractiontype='SFFloataccessType='inputOnly'
                               appinfo='range [0..1]'/>
 44                                <field name='set_keytype='MFFloataccessType='inputOnly'
                               appinfo='Array sequentially increasing [0..1]. Must have the same number of keys as keyValues.'/>
 45                                <field name='keyHolderNodetype='SFNodeaccessType='initializeOnly'>
 46                                     <ScalarInterpolator USE='KeyHolder'/>
 47                                </field>
 48                                <field name='key_changedtype='MFFloataccessType='outputOnly'
                               appinfo='Array sequentially increasing [0..1]. Must have the same number of keys as keyValues.'/>
 49                                <field name='set_keyValuetype='MFInt32accessType='inputOnly'
                               appinfo='Array of integer values. Must have the same number of keys as keyValues.'/>
 50                                <field name='keyValuetype='MFInt32accessType='initializeOnly'/>
 51                                <field name='keyValue_changedtype='MFInt32accessType='outputOnly'
                               appinfo='Array of integer values. Must have the same number of keys as keyValues.'/>
 52                                <!-- Regular interpolator-style output -->
 53                                <field name='value_changedtype='SFInt32accessType='outputOnly'/>
 54                                <!-- Utility methods -->
 55                                <field name='previoustype='SFBoolaccessType='inputOnly'/>
 56                                <field name='nexttype='SFBoolaccessType='inputOnly'/>
 57                                <field name='traceEnabledtype='SFBoolvalue='trueaccessType='initializeOnly'
                               appinfo='For development use only not for inclusion in specification implementations.'/>
 58                                <!-- Script-specific interfaces, not needed for node definition -->
 59                                <field name='previousFractiontype='SFFloatvalue='0.0accessType='initializeOnly'/>
 60                                <field name='nextIndextype='SFInt32value='0accessType='initializeOnly'/>
 61                                <field name='isValidtype='SFBoolvalue='trueaccessType='initializeOnly'/>
 62                                <field name='recheckValiditytype='SFBoolvalue='falseaccessType='initializeOnly'/>
 63                                <IS>
 64                                     <connect nodeField='set_fractionprotoField='set_fraction'/>
 65                                     <connect nodeField='set_keyprotoField='set_key'/>
 66                                     <connect nodeField='key_changedprotoField='key_changed'/>
 67                                     <connect nodeField='set_keyValueprotoField='set_keyValue'/>
 68                                     <connect nodeField='keyValueprotoField='keyValue'/>
 69                                     <connect nodeField='keyValue_changedprotoField='keyValue_changed'/>
 70                                     <connect nodeField='value_changedprotoField='value_changed'/>
 71                                     <connect nodeField='previousprotoField='previous'/>
 72                                     <connect nodeField='nextprotoField='next'/>
 73                                </IS>
  <![CDATA[
            
ecmascript:

var leftToRight;

function initialize()
{
	key      = keyHolderNode.key;
	tracePrint('Initializing a new IntegerSequencer.  key.length=' + key.length + '; keyValue.length=' + keyValue.length);
	tracePrint('key =' + key);
	tracePrint('keyValue =' + keyValue);

	validityCheck();
	setHalfKeyRange();

	// assume we start at first key, going left to right
	leftToRight = true;
	previousFraction = key[0];
	nextIndex = 1;  //validityCheck ensures minimum of 2 keys exist
}

function set_fraction(newFraction, timeStamp)
{
	if (recheckValidity) validityCheck();

	if (!isValid) return; //IntegerSequencer ignored

	//Bounds checking
	if (newFraction < key[0])
	{
		tracePrint('*** warning: fraction is less than first key.  fraction set to first key ***');
		newFraction = key[0];
	}
	else if (newFraction > key[key.length-1])
	{
		tracePrint('*** warning: fraction is greater than last key.  fraction set to last key ***');
		newFraction = key[key.length -1];
	}

	//Check animation direction
	if (newFraction < previousFraction && leftToRight == true)
	{
		if ((previousFraction - newFraction) > halfKeyRange) //looped around
		{
			nextIndex = 1;
		}
		else //just changed direction
		{
			leftToRight = false;
			nextIndex = nextIndex - 1;
            }
	}
	else if (newFraction > previousFraction && leftToRight == false)
	{
		if ((newFraction - previousFraction) < halfKeyRange) //looped around
		{
			nextIndex = key.length - 2;
		}
		else //just changed direction
		{
			leftToRight = true;
			nextIndex = nextIndex + 1;
            }
	}
	else if (newFraction == previousFraction)
	{ //no change, so no processing required
		return;
	}
	previousFraction = newFraction;

	if (leftToRight) // moving left to right
	{
		while (newFraction > key[nextIndex]) nextIndex++;

		if (newFraction == key[nextIndex])
			value_changed = keyValue[nextIndex];
		else	value_changed = keyValue[nextIndex -1];

		tracePrint('forward animation, fraction =' + newFraction);
		tracePrint('value_changed eventOut is:' + value_changed);
	}
	else // moving right to left
	{
		while (newFraction < key[nextIndex]) nextIndex--;

		if (newFraction == key[nextIndex])
			value_changed = keyValue[nextIndex];
		else	value_changed = keyValue[nextIndex + 1];

		tracePrint('backward animation, fraction =' + newFraction);
		tracePrint('value_changed eventOut is:' + value_changed);
	}
}

function set_key(newKey, timeStamp)
{
	key = newKey;
	keyHolderNode.key = newKey;
	setHalfKeyWidth();
	recheckValidity = true;
}

function set_keyValue(newKeyValue, timeStamp)
{
	keyValue = newKeyValue;
	recheckValidity = true;
}

function setHalfKeyRange()
{
	halfKeyRange = (key[key.length - 1] - key[0])/2.0;
}

function previous (value, timeStamp)
{
  if (value==true) // trigger on true events only
  {
	leftToRight = true;
	nextIndex = nextIndex - 2; // reset to previous
	if (nextIndex < 0) nextIndex = nextIndex + key.length;
	value_changed = keyValue[nextIndex];
	previousFraction = key[nextIndex];
	nextIndex++; // setup for next time, leftToRight
	if (nextIndex > key.length - 1) nextIndex = 0;
  }
}
function next (value, timeStamp)
{
  if (value==true) // trigger on true events only
  {
	leftToRight = true;
	value_changed = keyValue[nextIndex];
	previousFraction = key[nextIndex];
	nextIndex++; // setup for next time,leftToRight
	if (nextIndex > key.length - 1) nextIndex = 0;
  }
}

function validityCheck()
{
	//Check if lengths of key & keyValue arrays match
	if (key.length != keyValue.length)
	{
		alwaysPrint('*** error: key and keyValue arrays must be of the same length.  IntegerSequencer ignored ***');
		isValid = false;
		return;
	}
	//check to ensure minimum of 2 keys have been specified
	if (key.length < 2)
	{
		alwaysPrint('*** error: must contain at least 2 keys.  IntegerSequencer ignored ***');
		isValid = false;
		return;
	}

	//Check if key array has values in an non-decreasing order
	for (i = 1; i < key.length; i++)
	{
		tracePrint('i=' + i);

		if (key[i] < key [i-1])
		{
			alwaysPrint('*** error: key array values must be listed in a non-decreasing order.  IntegerSequencer ignored ***');
			isValid = false;
			return;
		}
	}
	isValid = true
	recheckValidity = false;
	key_changed = key;
	keyValue_changed = keyValue;
	return;
}

function tracePrint(outputString)
{
	if (traceEnabled) Browser.println ('[IntegerSequencer]' + outputString);
}

function alwaysPrint(outputString)
{
	Browser.println ('[IntegerSequencer]' + outputString);
}

          
]]>
 75                           </Script>
 76                      </Group>
 77                 </ProtoBody>
 78            </ProtoDeclare>
 79            <!-- ===============Example============== -->
 80            <Anchor description='IntegerSequencerExampleparameter='"target=_blank"'   url=' "IntegerSequencerExample.x3d" "https://savage.nps.edu/Savage/Tools/Animation/IntegerSequencerExample.x3d" "IntegerSequencerExample.wrl" "https://savage.nps.edu/Savage/Tools/Animation/IntegerSequencerExample.wrl" '>
 81                 <Shape>
 82                      <Text string='"IntegerSequencerPrototype" "defines a prototype" "" "Click text to see example scene" "IntegerSequencerExample"'>
 83                           <FontStyle justify='"MIDDLE" "MIDDLE"size='0.9'/>
 84                      </Text>
 85                      <Appearance>
 86                           <Material diffuseColor='1 1 0.2'/>
 87                      </Appearance>
 88                 </Shape>
 89            </Anchor>
 90       </Scene>
 91  </X3D>
<!--

<!--
Event Graph ROUTE Table shows event connections.
-->

<!-- to top Index for DEF nodes: KeyHolder, SequencerScript

Index for ProtoDeclare definition: IntegerSequencer
-->
X3D Tooltips element index: Anchor, Appearance, connect, field, FontStyle, Group, head, IS, Material, meta, ProtoBody, ProtoDeclare, ProtoInterface, ScalarInterpolator, Scene, Script, Shape, Switch, Text, WorldInfo, X3D, accessType and type, XML data types, field types

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

<!-- Color legend: X3D terminology <X3dNode  DEF='idNamefield='value'/> matches XML terminology <XmlElement  DEF='idNameattribute='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. -->