<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.2//EN" "http://www.web3d.org/specifications/x3d-3.2.dtd">
<X3D profile='Immersive' version='3.2 xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation =' http://www.web3d.org/specifications/x3d-3.2.xsd '>
<head>
<meta name='titlecontent='TestPosition2DFollower.x3d'/>
<meta name='descriptioncontent='X3D Follower example'/>
<meta name='creatorcontent='Herbert Stocker'/>
<meta name='translatorcontent='Don Brutzman'/>
<meta name='createdcontent='18 April 2006'/>
<meta name='translatedcontent='2 December 2011'/>
<meta name='modifiedcontent='20 October 2019'/>
<meta name='referencecontent='originals/test_Pos2DFollower.wrl'/>
<meta name='referencecontent='Stocker_06_Followers.pdf'/>
<meta name='referencecontent=' http://www.hersto.com/Publications/Followers '/>
<meta name='requirescontent='X3D version 3.2 or greater'/>
<meta name='subjectcontent='X3D Follower Chaser Damper'/>
<meta name=' warning content=' under development, instantReality works but BS Contact fails silently '/>
<meta name='referencecontent=' https://www.web3d.org/x3d/specifications/ISO-IEC-19775-1.2-X3D-AbstractSpecification/Part01/components/followers.html '/>
<meta name='referencecontent=' https://www.web3d.org/x3d/content/examples/X3dSceneAuthoringHints.html '/>
<meta name='identifiercontent=' https://www.web3d.org/x3d/content/examples/Basic/Followers/TestPosition2DFollower.x3d '/>
<meta name='generatorcontent='Vrml97ToX3dNist, http://ovrt.nist.gov/v2_x3d.html'/>
<meta name='generatorcontent='X3D-Edit 3.3, https://savage.nps.edu/X3D-Edit'/>
<meta name='licensecontent=' ../../license.html'/>
</head>
<!-- -->
<Scene>
<WorldInfo title='TestPosition2DFollower.x3d'/>
<Viewpoint fieldOfView='0.716position='0.0 0.0 15.0'/>
<NavigationInfo type='"NONE"'/>
<Group bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<!-- ROUTE information for PositionTouchSensor node:  [from hitTexCoord_changed to ScrTexCoordTo3D.A_in ] [from hitTexCoord_changed to PositionDamper2DNode.set_destination ] [from hitTexCoord_changed to PositionChaser2DNode.set_destination ] -->
<TouchSensor DEF='PositionTouchSensordescription='move ball to demonstrate PositionChaser2D, PositionDamper2D'/>
<Transform translation='0.0 0.0 -0.05bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Shape bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Appearance>
<Material diffuseColor='0.0 0.0 0.0emissiveColor='0.28 0.27 0.24'/>
</Appearance>
<Box size='10.0 10.0 0.1solid='true'/>
</Shape>
</Transform>
</Group>
<!-- ROUTE information for TrObjectDirect node:  [from ScrTexCoordTo3D.A_ot to translation ] -->
<Transform DEF='TrObjectDirectscale='0.8 0.8 0.8bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Shape bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Appearance>
<Material ambientIntensity='0.0333diffuseColor='0.02 0.24 0.53emissiveColor='0.01 0.12 0.27shininess='0.54specularColor='0.32 0.4 0.4'/>
</Appearance>
<Sphere DEF='GeomObjectradius='0.3'/>
</Shape>
</Transform>
<!-- ROUTE information for ScrTexCoordTo3D node:  [from PositionTouchSensor.hitTexCoord_changed to A_in ] [from PositionDamper2DNode.value_changed to B_in ] [from PositionChaser2DNode.value_changed to C_in ] [from A_ot to TrObjectDirect.translation ] [from B_ot to TrObjectDampered.translation ] [from C_ot to TrObjectFollowed.translation ] -->
<Script DEF='ScrTexCoordTo3D'>
<field name='A_ottype='SFVec3faccessType='outputOnly'/>
<field name='B_intype='SFVec2faccessType='inputOnly'/>
<field name='A_intype='SFVec2faccessType='inputOnly'/>
<field name='C_ottype='SFVec3faccessType='outputOnly'/>
<field name='B_ottype='SFVec3faccessType='outputOnly'/>
<field name='C_intype='SFVec2faccessType='inputOnly'/>
<![CDATA[
      
ecmascript:

function A_in(a)   { A_ot= (new SFVec3f(a.x, a.y, 0)).multiply(10).subtract(new SFVec3f(5, 5, 0)); }
function B_in(b)   { B_ot= (new SFVec3f(b.x, b.y, 0)).multiply(10).subtract(new SFVec3f(5, 5, 0)); }
function C_in(c)   { C_ot= (new SFVec3f(c.x, c.y, 0)).multiply(10).subtract(new SFVec3f(5, 5, 0)); }

    
]]>
</Script>
<ROUTE fromNode='PositionTouchSensorfromField='hitTexCoord_changedtoNode='ScrTexCoordTo3DtoField='A_in'/>
<ROUTE fromNode='ScrTexCoordTo3DfromField='A_ottoNode='TrObjectDirecttoField='translation'/>
<!-- ROUTE information for SwObjectDampered node:  [from ScrBtnMgr.WcDamper to whichChoice ] -->
<Switch DEF='SwObjectDamperedwhichChoice='0bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<!-- ROUTE information for TrObjectDampered node:  [from ScrTexCoordTo3D.B_ot to translation ] [from translation to ScrTrailer.DamperPos ] -->
<Transform DEF='TrObjectDamperedbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Shape bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Appearance DEF='AppObjectDampered'>
<Material ambientIntensity='0.0333diffuseColor='0.53 0.02 0.24emissiveColor='0.27 0.01 0.12shininess='0.54specularColor='0.4 0.32 0.4'/>
</Appearance>
<Sphere USE='GeomObject'/>
</Shape>
</Transform>
</Switch>
<!-- ROUTE information for PositionDamper2DNode node:  [from PositionTouchSensor.hitTexCoord_changed to set_destination ] [from value_changed to ScrTexCoordTo3D.B_in ] -->
<PositionDamper2D DEF='PositionDamper2DNodecontainerField='children'/>
<ROUTE fromNode='PositionTouchSensorfromField='hitTexCoord_changedtoNode='PositionDamper2DNodetoField='set_destination'/>
<ROUTE fromNode='PositionDamper2DNodefromField='value_changedtoNode='ScrTexCoordTo3DtoField='B_in'/>
<ROUTE fromNode='ScrTexCoordTo3DfromField='B_ottoNode='TrObjectDamperedtoField='translation'/>
<!-- ROUTE information for SwObjectFollowed node:  [from ScrBtnMgr.WcChaser to whichChoice ] -->
<Switch DEF='SwObjectFollowedwhichChoice='0bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<!-- ROUTE information for TrObjectFollowed node:  [from ScrTexCoordTo3D.C_ot to translation ] [from translation to ScrTrailer.ChaserPos ] -->
<Transform DEF='TrObjectFollowedbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Shape bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Appearance DEF='AppObjectFollowed'>
<Material ambientIntensity='0.0333diffuseColor='0.24 0.53 0.02emissiveColor='0.12 0.27 0.01shininess='0.54specularColor='0.4 0.4 0.32'/>
</Appearance>
<Sphere USE='GeomObject'/>
</Shape>
</Transform>
</Switch>
<!-- ROUTE information for PositionChaser2DNode node:  [from PositionTouchSensor.hitTexCoord_changed to set_destination ] [from value_changed to ScrTexCoordTo3D.C_in ] -->
<PositionChaser2D DEF='PositionChaser2DNodeduration='1.5containerField='children'/>
<ROUTE fromNode='PositionTouchSensorfromField='hitTexCoord_changedtoNode='PositionChaser2DNodetoField='set_destination'/>
<ROUTE fromNode='PositionChaser2DNodefromField='value_changedtoNode='ScrTexCoordTo3DtoField='C_in'/>
<ROUTE fromNode='ScrTexCoordTo3DfromField='C_ottoNode='TrObjectFollowedtoField='translation'/>
<ProtoDeclare name='ToggleButton'>
<ProtoInterface>
<field name='HottColortype='SFColorvalue='0.8 0.8 0.3accessType='initializeOnly'/>
<field name='initiallyOntype='SFBoolvalue='falseaccessType='initializeOnly'/>
<field name='ColdColortype='SFColorvalue='0.2 0.2 0.0accessType='initializeOnly'/>
<field name='isOntype='SFBoolaccessType='outputOnly'/>
</ProtoInterface>
<ProtoBody>
<Transform scale='0.4 0.4 0.4bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<TouchSensor DEF='Touchdescription='touch to activate'/>
<Shape DEF='ShRectbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Appearance>
<Material DEF='MatambientIntensity='0.04diffuseColor='0.0 0.0 0.0shininess='0.11'/>
</Appearance>
<IndexedFaceSet coordIndex='0 1 2 3 -1'>
<Coordinate point='-1.0 -1.0 0.0 1.0 -1.0 0.0 1.0 1.0 0.0 -1.0 1.0 0.0'/>
</IndexedFaceSet>
</Shape>
</Transform>
<!-- ROUTE information for ScrToggleButton node:  [from Tau to ColorDamperNode.tau ] [from Color to ColorDamperNode.set_destination ] [from Tau to Trace_ROUTE_ScrToggleButton.Tau_TO_Damp.tau.traceValue ] -->
<Script DEF='ScrToggleButton'>
<field name='TS_Touchedtype='SFTimeaccessType='inputOnly'/>
<field name='Colortype='SFColoraccessType='outputOnly'/>
<field name='isOntype='SFBoolaccessType='outputOnly'/>
<field name='ColdColortype='SFColoraccessType='initializeOnly'/>
<field name='Tautype='SFFloataccessType='outputOnly'/>
<field name='initiallyOntype='SFBoolaccessType='initializeOnly'/>
<field name='DamperSTheretype='SFBoolaccessType='inputOnly'/>
<field name='HottColortype='SFColoraccessType='initializeOnly'/>
<IS>
<connect nodeField='isOnprotoField='isOn'/>
<connect nodeField='ColdColorprotoField='ColdColor'/>
<connect nodeField='initiallyOnprotoField='initiallyOn'/>
<connect nodeField='HottColorprotoField='HottColor'/>
</IS>
<![CDATA[
          
ecmascript:

function DamperSThere()
{
    activate(initiallyOn);
}

function activate(a)
{
    isOn= a;
    Tau=  a? .1 : .2;
    Color= a? HottColor : ColdColor;
}

function set_id(i)
{
    id= i;
}

function TS_Touched()
{
    activate(!isOn);
}

        
]]>
</Script>
<!-- ROUTE information for ColorDamperNode node:  [from ScrToggleButton.Tau to tau ] [from ScrToggleButton.Color to set_destination ] -->
<ColorDamper DEF='ColorDamperNodeorder='1containerField='children'/>
<ROUTE fromNode='ScrToggleButtonfromField='TautoNode='ColorDamperNodetoField='tau'/>
<ROUTE fromNode='ScrToggleButtonfromField='ColortoNode='ColorDamperNodetoField='set_destination'/>
<Group bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<!-- ======= ROUTE Trace ============================================== -->
<!-- ROUTE information for Trace_ROUTE_ScrToggleButton.Tau_TO_Damp.tau node:  [from ScrToggleButton.Tau to traceValue ] -->
<Script DEF='Trace_ROUTE_ScrToggleButton.Tau_TO_Damp.taumustEvaluate='true'>
<!-- Trace ROUTEd values on X3D browser console -->
<field name='reportIntervaltype='SFTimevalue='1.0accessType='initializeOnly'
 appinfo='Sampling frequency in seconds (0 means all values)'/>

<field name='traceValuetype='SFFloataccessType='inputOnly'/>
<field name='timeStampPreviousReporttype='SFTimevalue='-1accessType='initializeOnly'/>
<![CDATA[
            
ecmascript:
    function traceValue (eventValue, timeStamp) {
      // input eventValue received for trace field
      if (timeStamp - timeStampPreviousReport >= reportInterval) {
        Browser.print ('Trace_ROUTE_ScrToggleButton.Tau_TO_Damp.tau type=SFFloat value=' + eventValue + '\n');
        timeStampPreviousReport = timeStamp;
      }
    }
    function timeOfDay (someTime) {
      hh = Math.floor (someTime /(60*60)) % 24;
      mm = Math.floor (someTime / 60)     % 60;
      ss = Math.floor (someTime)          % 60;
      if (hh < 9) hour   = '0' + hh;
      else        hour   =       hh;
      if (mm < 9) minute = '0' + mm;
      else        minute =       mm;
      if (ss < 9) second = '0' + ss;
      else        second =       ss;
      return '(' + hour + ':' + minute + ':' + second + ' GMT)';
    }

          
]]>
</Script>
<ROUTE fromNode='ScrToggleButtonfromField='TautoNode='Trace_ROUTE_ScrToggleButton.Tau_TO_Damp.tautoField='traceValue'/>
<!-- ======= ROUTE Trace block complete ===================================================== -->
</Group>
</ProtoBody>
</ProtoDeclare>
<Transform translation='-5.7 4.0 0.0bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<!-- ROUTE information for BtnDamper node:  [from isOn to ScrBtnMgr.BtnDamperIsOn ] -->
<ProtoInstance name='ToggleButtonDEF='BtnDamper'>
<fieldValue name='HottColorvalue='0.8 0.03 0.36'/>
<fieldValue name='initiallyOnvalue='true'/>
<fieldValue name='ColdColorvalue='0.2 0.0080 0.09'/>
</ProtoInstance>
</Transform>
<Transform translation='-8.0 3.9 0.0bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Shape bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Appearance DEF='AppLabels'>
<Material diffuseColor='0.0 0.0 0.0emissiveColor='0.8 0.8 0.8'/>
</Appearance>
<Text string='"Damper"'>
<FontStyle DEF='FntLabelsfamily='"Arial" "SANS"size='0.5'/>
</Text>
</Shape>
</Transform>
<Transform translation='-5.7 2.8 0.0bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<!-- ROUTE information for BtnChaser node:  [from isOn to ScrBtnMgr.BtnChaserIsOn ] -->
<ProtoInstance name='ToggleButtonDEF='BtnChaser'>
<fieldValue name='HottColorvalue='0.36 0.8 0.03'/>
<fieldValue name='initiallyOnvalue='true'/>
<fieldValue name='ColdColorvalue='0.09 0.2 0.0080'/>
</ProtoInstance>
</Transform>
<Transform translation='-8.0 2.7 0.0bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Shape bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Appearance USE='AppLabels'/>
<Text string='"Chaser"'>
<FontStyle USE='FntLabels'/>
</Text>
</Shape>
</Transform>
<!-- ROUTE information for ScrBtnMgr node:  [from BtnDamper.isOn to BtnDamperIsOn ] [from BtnChaser.isOn to BtnChaserIsOn ] [from WcDamper to SwObjectDampered.whichChoice ] [from WcChaser to SwObjectFollowed.whichChoice ] [from WcDamper to SwDamperTrail.whichChoice ] [from WcChaser to SwChaserTrail.whichChoice ] -->
<Script DEF='ScrBtnMgr'>
<field name='BtnChaserIsOntype='SFBoolaccessType='inputOnly'/>
<field name='WcDampertype='SFInt32accessType='outputOnly'/>
<field name='WcChasertype='SFInt32accessType='outputOnly'/>
<field name='BtnDamperIsOntype='SFBoolaccessType='inputOnly'/>
<![CDATA[
      
ecmascript:

function BtnDamperIsOn(on)
{
    WcDamper= on? 0:-1;
}

function BtnChaserIsOn(on)
{
    WcChaser= on? 0:-1;
}

    
]]>
</Script>
<ROUTE fromNode='BtnDamperfromField='isOntoNode='ScrBtnMgrtoField='BtnDamperIsOn'/>
<ROUTE fromNode='BtnChaserfromField='isOntoNode='ScrBtnMgrtoField='BtnChaserIsOn'/>
<ROUTE fromNode='ScrBtnMgrfromField='WcDampertoNode='SwObjectDamperedtoField='whichChoice'/>
<ROUTE fromNode='ScrBtnMgrfromField='WcChasertoNode='SwObjectFollowedtoField='whichChoice'/>
<!-- ROUTE information for SwDamperTrail node:  [from ScrBtnMgr.WcDamper to whichChoice ] -->
<Switch DEF='SwDamperTrailwhichChoice='0bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Group DEF='GrDamperTrailbboxCenter='0 0 0bboxSize='-1 -1 -1'/>
</Switch>
<!-- ROUTE information for SwChaserTrail node:  [from ScrBtnMgr.WcChaser to whichChoice ] -->
<Switch DEF='SwChaserTrailwhichChoice='0bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Group DEF='GrChaserTrailbboxCenter='0 0 0bboxSize='-1 -1 -1'/>
</Switch>
<!-- ROUTE information for TmrTrail node:  [from cycleTime to ScrTrailer.Tick ] -->
<TimeSensor DEF='TmrTrailcycleInterval='0.020000000000000004loop='true'/>
<!-- ROUTE information for ScrTrailer node:  [from TmrTrail.cycleTime to Tick ] [from TrObjectDampered.translation to DamperPos ] [from TrObjectFollowed.translation to ChaserPos ] -->
<Script DEF='ScrTrailerdirectOutput='true'>
<field name='cShapeDamperTrailPointtype='SFNodeaccessType='initializeOnly'>
<Shape bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Appearance USE='AppObjectDampered'/>
<Sphere DEF='GeomTrailradius='0.1'/>
</Shape>
</field>
<field name='lastDamperPostype='SFVec3fvalue='0.0 0.0 0.0accessType='initializeOnly'/>
<field name='ChaserTrailstype='MFNodeaccessType='initializeOnly'>
<!-- no initialization nodes since this is a local field to hold content -->
</field>
<field name='cShapeChaserTrailPointtype='SFNodeaccessType='initializeOnly'>
<Shape bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Appearance USE='AppObjectFollowed'/>
<Sphere USE='GeomTrail'/>
</Shape>
</field>
<field name='DamperTrailstype='MFNodeaccessType='initializeOnly'>
<!-- no initialization nodes since this is a local field to hold content -->
</field>
<field name='GrChaserTrailtype='SFNodeaccessType='initializeOnly'>
<Group USE='GrChaserTrailbboxCenter='0 0 0bboxSize='-1 -1 -1'/>
</field>
<field name='ChaserPostype='SFVec3faccessType='inputOnly'/>
<field name='cNumTrailPointstype='SFInt32value='35accessType='initializeOnly'/>
<field name='lastChaserPostype='SFVec3fvalue='0.0 0.0 0.0accessType='initializeOnly'/>
<field name='Ticktype='SFTimeaccessType='inputOnly'/>
<field name='DamperPostype='SFVec3faccessType='inputOnly'/>
<field name='GrDamperTrailtype='SFNodeaccessType='initializeOnly'>
<Group USE='GrDamperTrailbboxCenter='0 0 0bboxSize='-1 -1 -1'/>
</field>
<![CDATA[
      
ecmascript:

function initialize()
{
    DamperTrails.length=
    ChaserTrails.length= cNumTrailPoints;

    for(var C= 0; C<cNumTrailPoints; C++ )
    {
        DamperTrails[C]= new SFNode('Transform{}');
        ChaserTrails[C]= new SFNode('Transform{}');

        DamperTrails[C].children[0]= cShapeDamperTrailPoint;
        ChaserTrails[C].children[0]= cShapeChaserTrailPoint;
    }

    GrDamperTrail.children= DamperTrails;
    GrChaserTrail.children= ChaserTrails;
}

function DamperPos(Pos)
{
    lastDamperPos= Pos;
}

function ChaserPos(Pos)
{
    lastChaserPos= Pos;
}

function Tick()
{
    for(var C= cNumTrailPoints - 1; C>0; C-- )
    {
        DamperTrails[C].translation= DamperTrails[  C - 1].translation;
        ChaserTrails[C].translation= ChaserTrails[C - 1].translation;
    }

    DamperTrails[0].translation= lastDamperPos;
    ChaserTrails[0].translation= lastChaserPos;
}

    
]]>
</Script>
<ROUTE fromNode='TmrTrailfromField='cycleTimetoNode='ScrTrailertoField='Tick'/>
<ROUTE fromNode='TrObjectDamperedfromField='translationtoNode='ScrTrailertoField='DamperPos'/>
<ROUTE fromNode='TrObjectFollowedfromField='translationtoNode='ScrTrailertoField='ChaserPos'/>
<ROUTE fromNode='ScrBtnMgrfromField='WcDampertoNode='SwDamperTrailtoField='whichChoice'/>
<ROUTE fromNode='ScrBtnMgrfromField='WcChasertoNode='SwChaserTrailtoField='whichChoice'/>
</Scene>
</X3D>
<!--

Index for ProtoDeclare definition : ToggleButton

Index for DEF nodes : AppLabels, AppObjectDampered, AppObjectFollowed, BtnChaser, BtnDamper, ColorDamperNode, FntLabels, GeomObject, GeomTrail, GrChaserTrail, GrDamperTrail, Mat, PositionChaser2DNode, PositionDamper2DNode, PositionTouchSensor, ScrBtnMgr, ScrTexCoordTo3D, ScrToggleButton, ScrTrailer, ShRect, SwChaserTrail, SwDamperTrail, SwObjectDampered, SwObjectFollowed, TmrTrail, Touch, Trace_ROUTE_ScrToggleButton.Tau_TO_Damp.tau, TrObjectDampered, TrObjectDirect, TrObjectFollowed

Index for Viewpoint image : Viewpoint_1
-->

<!-- Color key: <X3dNode DEF='idName' field='value'/> matches <XmlElement DEF='idName' attribute='value'/>
(Light blue background: behavior node) (Grey background: inserted documentation) (Magenta background: X3D Extensibility)
    <Prototype name='ProtoName'> <field name='fieldName'/> </Prototype> -->

<!-- Additional help information about X3D scenes: X3D Resources, X3D Scene Authoring Hints and X3D Tooltips -->