<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">package Basic.Followers;

import org.web3d.x3d.jsail.Core.*;
import org.web3d.x3d.jsail.fields.*;
import org.web3d.x3d.jsail.Geometry3D.*;
import org.web3d.x3d.jsail.Grouping.*;
import org.web3d.x3d.jsail.Navigation.*;
import org.web3d.x3d.jsail.PointingDeviceSensor.*;
import org.web3d.x3d.jsail.Scripting.*;
import org.web3d.x3d.jsail.Shape.*;
import org.web3d.x3d.jsail.Time.*;

// Javadoc metadata annotations follow, see below for X3DJSAIL Java source code.
/**
 * &lt;p&gt; X3D Follower example. &lt;/p&gt;
 &lt;p&gt; Related links: Catalog page &lt;a href="../../../Followers/SliderIndex.html" target="_blank"&gt;Slider&lt;/a&gt;,  source &lt;a href="../../../Followers/Slider.java"&gt;Slider.java&lt;/a&gt;, &lt;a href="https://www.web3d.org/x3d/content/examples/X3dResources.html" target="_blank"&gt;X3D Resources&lt;/a&gt;, &lt;a href="https://www.web3d.org/x3d/content/examples/X3dSceneAuthoringHints.html" target="_blank"&gt;X3D Scene Authoring Hints&lt;/a&gt;, and &lt;a href="https://www.web3d.org/x3d/content/X3dTooltips.html" target="_blank"&gt;X3D Tooltips&lt;/a&gt;. &lt;/p&gt;
	&lt;table style="color:black; border:0px solid; border-spacing:10px 0px;"&gt;
        &lt;caption&gt;Scene Meta Information&lt;/caption&gt;
		&lt;tr style="background-color:silver; border-color:silver;"&gt;
			&lt;td style="text-align:center; padding:10px 0px;"&gt;&lt;i&gt;meta tags&lt;/i&gt;&lt;/td&gt;
			&lt;td style="text-align:left;   padding:10px 0px;"&gt;&amp;nbsp; Document Metadata &lt;/td&gt;
		&lt;/tr&gt;

		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; title &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; &lt;a href="../../../Followers/Slider.x3d"&gt;Slider.x3d&lt;/a&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; description &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; X3D Follower example &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; creator &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; Herbert Stocker &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; translator &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; Don Brutzman &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; created &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; 18 April 2006 &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; translated &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; 2 December 2011 &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; modified &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; 2 January 2025 &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; reference &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; originals/test_Sliders.wrl &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; reference &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; &lt;a href="../../../Followers/Stocker_06_Followers.pdf"&gt;Stocker_06_Followers.pdf&lt;/a&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; reference &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; &lt;a href="http://www.hersto.com/Publications/Followers" target="_blank"&gt;http://www.hersto.com/Publications/Followers&lt;/a&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; requires &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; X3D version 3.2 or greater &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; subject &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; X3D Follower Chaser Damper &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="color:burntorange"&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; warning &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; under development &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; reference &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; &lt;a href="https://www.web3d.org/x3d/content/examples/X3dSceneAuthoringHints.html" target="_blank"&gt;https://www.web3d.org/x3d/content/examples/X3dSceneAuthoringHints.html&lt;/a&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; identifier &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; &lt;a href="https://www.web3d.org/x3d/content/examples/Basic/Followers/Slider.x3d" target="_blank"&gt;https://www.web3d.org/x3d/content/examples/Basic/Followers/Slider.x3d&lt;/a&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; generator &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; Vrml97ToX3dNist, &lt;a href="http://ovrt.nist.gov/v2_x3d.html" target="_blank"&gt;http://ovrt.nist.gov/v2_x3d.html&lt;/a&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; generator &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; X3D-Edit 3.3, &lt;a href="https://savage.nps.edu/X3D-Edit" target="_blank"&gt;https://savage.nps.edu/X3D-Edit&lt;/a&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="text-align:right; vertical-align: text-top;"&gt; &lt;i&gt; license &lt;/i&gt; &lt;/td&gt;
			&lt;td&gt; &lt;a href="../../../Followers/../../license.html"&gt;../../license.html&lt;/a&gt; &lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="background-color:silver; border-color:silver;"&gt;
			&lt;td style="text-align:center;" colspan="2"&gt;  &amp;nbsp; &lt;/td&gt;
		&lt;/tr&gt;
	&lt;/table&gt;

	&lt;p&gt;
		This program uses the
		&lt;a href="https://www.web3d.org/specifications/java/X3DJSAIL.html" target="_blank"&gt;X3D Java Scene Access Interface Library (X3DJSAIL)&lt;/a&gt;.
		It has been produced using the 
		&lt;a href="https://www.web3d.org/x3d/stylesheets/X3dToJava.xslt" target="_blank"&gt;X3dToJava.xslt&lt;/a&gt;
		stylesheet
	       (&lt;a href="https://sourceforge.net/p/x3d/code/HEAD/tree/www.web3d.org/x3d/stylesheets/X3dToJava.xslt" target="_blank"&gt;version control&lt;/a&gt;)
                which is used to create Java source code from an original &lt;code&gt;.x3d&lt;/code&gt; model.
	&lt;/p&gt;

	* @author Herbert Stocker
 */

public class Slider
{
	/** Default constructor to create this object. */
	public Slider ()
	{
	  initialize();
	}

	/** Create and initialize the X3D model for this object. */
	public final void initialize()
	{
            try { // catch-all
  x3dModel = new X3D().setProfile(X3D.PROFILE_IMMERSIVE).setVersion(X3D.VERSION_3_2)
  .setHead(new head()
    .addMeta(new meta().setName(meta.NAME_TITLE      ).setContent("Slider.x3d"))
    .addMeta(new meta().setName(meta.NAME_DESCRIPTION).setContent("X3D Follower example"))
    .addMeta(new meta().setName(meta.NAME_CREATOR    ).setContent("Herbert Stocker"))
    .addMeta(new meta().setName(meta.NAME_TRANSLATOR ).setContent("Don Brutzman"))
    .addMeta(new meta().setName(meta.NAME_CREATED    ).setContent("18 April 2006"))
    .addMeta(new meta().setName(meta.NAME_TRANSLATED ).setContent("2 December 2011"))
    .addMeta(new meta().setName(meta.NAME_MODIFIED   ).setContent("2 January 2025"))
    .addMeta(new meta().setName(meta.NAME_REFERENCE  ).setContent("originals/test_Sliders.wrl"))
    .addMeta(new meta().setName(meta.NAME_REFERENCE  ).setContent("Stocker_06_Followers.pdf"))
    .addMeta(new meta().setName(meta.NAME_REFERENCE  ).setContent("http://www.hersto.com/Publications/Followers"))
    .addMeta(new meta().setName(meta.NAME_REQUIRES   ).setContent("X3D version 3.2 or greater"))
    .addMeta(new meta().setName(meta.NAME_SUBJECT    ).setContent("X3D Follower Chaser Damper"))
    .addMeta(new meta().setName(meta.NAME_WARNING    ).setContent("under development"))
    .addMeta(new meta().setName(meta.NAME_REFERENCE  ).setContent("https://www.web3d.org/x3d/content/examples/X3dSceneAuthoringHints.html"))
    .addMeta(new meta().setName(meta.NAME_IDENTIFIER ).setContent("https://www.web3d.org/x3d/content/examples/Basic/Followers/Slider.x3d"))
    .addMeta(new meta().setName(meta.NAME_GENERATOR  ).setContent("Vrml97ToX3dNist, http://ovrt.nist.gov/v2_x3d.html"))
    .addMeta(new meta().setName(meta.NAME_GENERATOR  ).setContent("X3D-Edit 3.3, https://savage.nps.edu/X3D-Edit"))
    .addMeta(new meta().setName(meta.NAME_LICENSE    ).setContent("../../license.html")))
  .setScene(new Scene()
    .addChild(new WorldInfo().setInfo(new String[] {" The original versions of the PROTO Slider was written by me, Herbert Stocker. The original versions and some test and demonstration Worlds can be found at http://www.hersto.de/ . "," You can use and modify the PROTO in this file if you keep the credit information valid and if you do not remove the link to the originating site http://www.hersto.de/ . In brief, keep this WorldInfo node along with the Proto. "," Please send a message to hersto@hersto.de where you describe how you use or improved the nodes. Especially if you included the improved versions. "}).setTitle("Copyright (C) 2002 by Herbert Stocker (AKA hersto)"))
    .addChild(new ProtoDeclare("Slider").setName("Slider")
      .setProtoInterface(new ProtoInterface()
        .addField(new field().setName("initial_position").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.5))
        .addField(new field().setName("credits").setType(field.TYPE_MFSTRING).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(new String[] {"Initial idea and copyright by Herbert Stocker http://www.hersto.com/"}))
        .addField(new field().setName("radiusKnob").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTOUTPUT).setValue(0.3))
        .addField(new field().setName("radiusStick").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTOUTPUT).setValue(0.2))
        .addField(new field().setName("silently_set_unfiltered_position").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTONLY))
        .addField(new field().setName("min").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTOUTPUT).setValue(0.0))
        .addField(new field().setName("position_changed").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
        .addField(new field().setName("appearance").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INPUTOUTPUT)
          .addChild(new Appearance()
            .setMaterial(new Material())))
        .addField(new field().setName("smoothMovements").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INPUTOUTPUT).setValue(true))
        .addField(new field().setName("set_position").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTONLY))
        .addField(new field().setName("pageSize").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTOUTPUT).setValue(0.2))
        .addField(new field().setName("max").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTOUTPUT).setValue(1.0))
        .addField(new field().setName("unfiltered_position_changed").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
        .addField(new field().setName("silently_set_position").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTONLY))
        .addField(new field().setName("set_unfiltered_position").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTONLY))
        .addField(new field().setName("height").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTOUTPUT).setValue(2.0))
        .addField(new field().setName("positionInt_changed").setType(field.TYPE_SFINT32).setAccessType(field.ACCESSTYPE_OUTPUTONLY)))
      .setProtoBody(new ProtoBody()
        .addChild(new Billboard()
          .addChild(new Transform("TrStickAbove")
            .addChild(new TouchSensor("TchPgUp").setDescription("touch to activate PgUp"))
            .addChild(new Shape()
              .setIS(new IS()
                .addConnect(new connect().setNodeField("appearance").setProtoField("appearance")))
              .setGeometry(new Cylinder().setHeight(1.0))))
          .addChild(new Transform("TrStickBelow")
            .addChild(new TouchSensor("TchPgDown").setDescription("touch to activate PgDown"))
            .addChild(new Shape()
              .setIS(new IS()
                .addConnect(new connect().setNodeField("appearance").setProtoField("appearance")))
              .setGeometry(new Cylinder().setHeight(1.0))))
          .addChild(new Group()
            .addChild(new PlaneSensor("SensKnob").setDescription("touch to activate").setAutoOffset(false).setMaxPosition(0.0,-1.0))
            .addChild(new Transform("TrKnob")
              .addChild(new Shape()
                .setIS(new IS()
                  .addConnect(new connect().setNodeField("appearance").setProtoField("appearance")))
                .setGeometry(new Cylinder().setHeight(1.0))))))
        .addChild(new ProtoDeclare("EFFS").setName("EFFS")
          .setProtoInterface(new ProtoInterface()
            .addField(new field().setName("height").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTOUTPUT).setValue(2.0))
            .addField(new field().setName("max").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTOUTPUT).setValue(1.0))
            .addField(new field().setName("radiusKnob").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTOUTPUT).setValue(0.5))
            .addField(new field().setName("pageSize").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTOUTPUT).setValue(0.2))
            .addField(new field().setName("smoothMovements").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INPUTOUTPUT).setValue(true))
            .addField(new field().setName("radiusStick").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTOUTPUT).setValue(0.25))
            .addField(new field().setName("min").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTOUTPUT).setValue(0.0)))
          .setProtoBody(new ProtoBody()
            .addChild(new Group())))
        .addChild(new ProtoInstance("EFFS", "EFFS").setContainerField("children")
          .addFieldValue(new fieldValue().setName("max").setValue(1.0))
          .addFieldValue(new fieldValue().setName("height").setValue(2.0))
          .addFieldValue(new fieldValue().setName("pageSize").setValue(0.2))
          .addFieldValue(new fieldValue().setName("radiusKnob").setValue(0.5))
          .addFieldValue(new fieldValue().setName("smoothMovements").setValue(true))
          .addFieldValue(new fieldValue().setName("radiusStick").setValue(0.25))
          .addFieldValue(new fieldValue().setName("min").setValue(0.0)))
        .addChild(new TimeSensor("Timer").setLoop(true))
        .addChild(new Script("Worker").setDirectOutput(true).setSourceCode("""
ecmascript:

function initialize()
{            
    positionSmo1= position;
    positionSmo2= position;
    positionSmo3= position;

    min=             EFFS.min;
    max=             EFFS.max;
    pageSize=        EFFS.pageSize;
    height=          EFFS.height;
    radiusKnob=      EFFS.radiusKnob;
    radiusStick=     EFFS.radiusStick;
    smoothMovements= EFFS.smoothMovements;

    // work around the initialization bug in Contact 5.
    if(   Browser.getName() == 'blaxxunCC3D'
       &amp;&amp; Browser.getVersion() &lt;= 5.104
       &amp;&amp; !position &amp;&amp; !min &amp;&amp; !max &amp;&amp; !pageSize &amp;&amp; !height &amp;&amp; !radiusKnob &amp;&amp; !radiusStick
      )
    {
        position= .5;
        min= 0;
        max= 1;
        pageSize= .2;
        height= 2;
        radiusKnob= .3;
        radiusStick= .2;

        positionSmo1= 
        positionSmo2= 
        positionSmo3=
            position;
    }


    Update();

    Timer.enabled= true; // TBD: Shouldn't we start with false?
}

function set_min(m)           {          min= m;  Update();          }
function set_max(m)           {          max= m;  Update();          }
function set_pageSize(s)      {     pageSize= s;  Update();          }
function set_height(h)        {       height= h;  UpdateGeometry();  }
function set_radiusKnob(r)    {   radiusKnob= r;  UpdateGeometry();  }
function set_radiusStick(r)   {  radiusStick= r;  UpdateGeometry();  }
function set_position(p) 
{ 
    silent= false; 
    snapTime= 0; 
    position= snapToInt? Math.floor(p + .5) : p;
    Update();
}

function set_smooothMovements(s)
{
    smoothMovements= s;
    Update();
}

function silently_set_position(p) 
{ 
    silent= true;
    snapTime= 0;
    position= snapToInt? Math.floor(p + .5) : p;
    Update();        
}

function silently_set_unfiltered_position(p, now)  
{ 
    silent= true; 
    snapTime= 0;
    position= positionSmo1= positionSmo2= positionSmo3= p;
    snapTime= now + .1;
    Update(); 
}

 function set_unfiltered_position(p, now)  
{ 
    snapTime= 0;
    position= positionSmo1= positionSmo2= positionSmo3= p;
    snapTime= now + .1;
    Update(); 
}

function incPage(t, now)
{
    silent= false;
    position+= pageSize;
    snapTime= now + .3;
    Update();
}

function decPage(t, now)
{
    silent= false;
    position-= pageSize;
    snapTime= now + .3;
    Update();
}

function SensKnob_isActive(a, now)
{
    if(a)
    {
        SensKnobOrigin= smoothMovements? positionSmo3 : position;  // TBD: Da stimmt noch was nicht.
        SmoothTau1= .07;
        SmoothTau2= .001;
        SmoothTau3= .001;
//                last_SensKnob_translationChange= SensKnob_translationChanged;
    }else{
        SmoothTau1= .06;
        SmoothTau2= .06;
        SmoothTau3= .06;
        snapTime=   now;
    }
}

function SensKnob_translationChanged(t, now)
{
    silent= false;
//            if(t.subtract(last_SensKnob_translationChange).length() &gt; .0001 )
//            {
        position= SensKnobOrigin + ( height? t.y * (max - min) / (height - KnobSize)
                                           : 0
                                   );
//                snapTime= now + .3;

//                last_SensKnob_translationChange= t;
//            }
    Update();
}

function Update()
{
    UpdateLogic();

    UpdateGeometry();

    if(smoothMovements) 
    {
        setUPC(position);
    }else{
        setUPC(position);
        positionSmo1= position;
        positionSmo2= position;
        positionSmo3= position;
        setPC(position);
    }
}

function UpdateLogic()
{
    if(max &lt; min)
        max= min;

    if(position     &gt; max)    position=     max;
    if(positionSmo1 &gt; max)    positionSmo1= max;
    if(positionSmo2 &gt; max)    positionSmo2= max;
    if(positionSmo3 &gt; max)    positionSmo3= max;

    if(position     &lt; min)    position=     min;
    if(positionSmo1 &lt; min)    positionSmo1= min;
    if(positionSmo2 &lt; min)    positionSmo2= min;
    if(positionSmo3 &lt; min)    positionSmo3= min;
}

function UpdateGeometry()
{
    KnobSize= max - min? pageSize / (max - min) * height
                       : height
                       ;

    KnobCenterPos= max - min? ( ( smoothMovements? positionSmo3
                                                 : position
                                )
                              - (max + min)/2
                              ) / (max - min) * (height - KnobSize)
                            : 0
                            ;

    TrKnob.scale=             new SFVec3f(radiusKnob,   KnobSize,                     radiusKnob);
    TrKnob.translation=       new SFVec3f(0,            KnobCenterPos,                0);

    TrStickAbove.scale=       new SFVec3f(radiusStick,  (height/2 - KnobCenterPos),   radiusStick);
    TrStickAbove.translation= new SFVec3f(0,           (height/2 + KnobCenterPos)/2, 0          );

    TrStickBelow.scale=       new SFVec3f(radiusStick, (KnobCenterPos - -height/2),   radiusStick);
    TrStickBelow.translation= new SFVec3f(0,           (KnobCenterPos + -height/2)/2, 0          );
}

function Tick(now)
{
    if(!lastTick)
    {
        lastTick= now;
return;
    }

    var Delta= now - lastTick;

    if(smoothMovements)  // TBD: The timer should be completely off if !Smoothmovements.
    {
        positionSmo1= position     + (positionSmo1 - position    ) * Math.exp(-Delta/SmoothTau1);
        positionSmo2= positionSmo1 + (positionSmo2 - positionSmo1) * Math.exp(-Delta/SmoothTau2);
        positionSmo3= positionSmo2 + (positionSmo3 - positionSmo2) * Math.exp(-Delta/SmoothTau3);

        UpdateGeometry();

        setPC(positionSmo3);
    }

    if(snapToInt)
        if(snapTime &amp;&amp; now &gt;= snapTime)
        {
            var newPos= Math.floor(position + .5);
            SensKnobOrigin+= newPos - position;
            position= newPos;
            snapTime= 0;
        }


    //TBD: Set Timer.enabled

    lastTick= now;
}

function setUPC(value)
{
    if(unfiltered_position_changed != value || initialUnfilteredUpdate)
        if(!silent) unfiltered_position_changed= value;

    initialUnfilteredUpdate= false;
}

function setPC(value)
{
    if(position_changed != value || initialUpdate) 
        if(!silent) position_changed= value;

    if(Math.floor(position_changed + .5) != positionInt_changed || initialUpdate)
        if(!silent) positionInt_changed= Math.floor(position_changed + .5);

    initialUpdate= false;
}
""")
          .addField(new field().setName("height").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(2.0))
          .addField(new field().setName("set_max").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("silent").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(false))
          .addField(new field().setName("lastTick").setType(field.TYPE_SFTIME).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.0))
          .addField(new field().setName("set_pageSize").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("decPage").setType(field.TYPE_SFTIME).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("set_radiusStick").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("set_height").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("position_changed").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
          .addField(new field().setName("Timer").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY)
            .addChild(new TimeSensor().setUSE("Timer")))
          .addField(new field().setName("set_position").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("snapTime").setType(field.TYPE_SFTIME).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.0))
          .addField(new field().setName("TrStickAbove").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY)
            .addChild(new Transform().setUSE("TrStickAbove")))
          .addField(new field().setName("set_radiusKnob").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("smoothMovements").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(true))
          .addField(new field().setName("max").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(1.0))
          .addField(new field().setName("initialUpdate").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(true))
          .addField(new field().setName("EFFS").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY)
            .addChild(new ProtoInstance("EFFS").setUSE("EFFS").setContainerField("children")))
          .addField(new field().setName("SensKnobOrigin").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.0))
          .addField(new field().setName("pageSize").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.2))
          .addField(new field().setName("positionInt_changed").setType(field.TYPE_SFINT32).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
          .addField(new field().setName("SmoothTau3").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.05))
          .addField(new field().setName("SmoothTau2").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.05))
          .addField(new field().setName("SmoothTau1").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.05))
          .addField(new field().setName("set_min").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("SensKnob_isActive").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("KnobSize").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.0))
          .addField(new field().setName("silently_set_position").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("initialUnfilteredUpdate").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(true))
          .addField(new field().setName("positionSmo3").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.0))
          .addField(new field().setName("snapToInt").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(false))
          .addField(new field().setName("positionSmo2").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.0))
          .addField(new field().setName("set_unfiltered_position").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("positionSmo1").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.0))
          .addField(new field().setName("silently_set_unfiltered_position").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("radiusStick").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.25))
          .addField(new field().setName("KnobCenterPos").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.0))
          .addField(new field().setName("position").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY))
          .addField(new field().setName("SensKnob_translationChanged").setType(field.TYPE_SFVEC3F).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("radiusKnob").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.5))
          .addField(new field().setName("TrStickBelow").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY)
            .addChild(new Transform().setUSE("TrStickBelow")))
          .addField(new field().setName("TchPgUp").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY)
            .addChild(new TouchSensor().setUSE("TchPgUp")))
          .addField(new field().setName("incPage").setType(field.TYPE_SFTIME).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("unfiltered_position_changed").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_OUTPUTONLY))
          .addField(new field().setName("Tick").setType(field.TYPE_SFTIME).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("set_smooothMovements").setType(field.TYPE_SFBOOL).setAccessType(field.ACCESSTYPE_INPUTONLY))
          .addField(new field().setName("min").setType(field.TYPE_SFFLOAT).setAccessType(field.ACCESSTYPE_INITIALIZEONLY).setValue(0.0))
          .addField(new field().setName("TchPgDown").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY)
            .addChild(new TouchSensor().setUSE("TchPgDown")))
          .addField(new field().setName("TrKnob").setType(field.TYPE_SFNODE).setAccessType(field.ACCESSTYPE_INITIALIZEONLY)
            .addChild(new Transform().setUSE("TrKnob")))
          .setIS(new IS()
            .addConnect(new connect().setNodeField("position_changed").setProtoField("position_changed"))
            .addConnect(new connect().setNodeField("set_position").setProtoField("set_position"))
            .addConnect(new connect().setNodeField("positionInt_changed").setProtoField("positionInt_changed"))
            .addConnect(new connect().setNodeField("silently_set_position").setProtoField("silently_set_position"))
            .addConnect(new connect().setNodeField("set_unfiltered_position").setProtoField("set_unfiltered_position"))
            .addConnect(new connect().setNodeField("silently_set_unfiltered_position").setProtoField("silently_set_unfiltered_position"))
            .addConnect(new connect().setNodeField("position").setProtoField("initial_position"))
            .addConnect(new connect().setNodeField("unfiltered_position_changed").setProtoField("unfiltered_position_changed"))))))
    .addComments(" TODO anchor link "));
            }
            catch (Exception ex)
            {       
                System.err.println ("*** Further hints on X3DJSAIL errors and exceptions at");
                System.err.println ("*** https://www.web3d.org/specifications/java/X3DJSAIL.html");
                throw (ex);
            }
	}
	// end of initialize() method

	/** The initialized model object, created within initialize() method. */
	private X3D x3dModel;

	/** 
	 * Provide a 
	 * &lt;a href="https://dzone.com/articles/java-copy-shallow-vs-deep-in-which-you-will-swim" target="_blank"&gt;shallow copy&lt;/a&gt;
	 * of the X3D model.
	 * @see &lt;a href="https://www.web3d.org/specifications/java/javadoc/org/web3d/x3d/jsail/Core/X3D.html"&gt;X3D&lt;/a&gt;
	 * @return Slider model
	 */
	public X3D getX3dModel()
	{	  
		return x3dModel;
	}
	   
    /** 
     * Default main() method provided for test purposes, uses CommandLine to set global ConfigurationProperties for this object.
     * @param args array of input parameters, provided as arguments
     * @see &lt;a href="https://www.web3d.org/specifications/java/javadoc/org/web3d/x3d/jsail/Core/X3D.html#handleArguments-java.lang.String:A-"&gt;X3D.handleArguments(args)&lt;/a&gt;
     * @see &lt;a href="https://www.web3d.org/specifications/java/javadoc/org/web3d/x3d/jsail/Core/X3D.html#validationReport--"&gt;X3D.validationReport()&lt;/a&gt;
     * @see &lt;a href="https://www.web3d.org/specifications/java/javadoc/org/web3d/x3d/jsail/CommandLine.html"&gt;CommandLine&lt;/a&gt;
     * @see &lt;a href="https://www.web3d.org/specifications/java/javadoc/org/web3d/x3d/jsail/CommandLine.html#USAGE"&gt;CommandLine.USAGE&lt;/a&gt;
     * @see &lt;a href="https://www.web3d.org/specifications/java/javadoc/org/web3d/x3d/jsail/ConfigurationProperties.html"&gt;ConfigurationProperties&lt;/a&gt;
     */
    public static void main(String args[])
    {
        System.out.println("Build this X3D model, showing validation diagnostics...");
        X3D thisExampleX3dModel = new Slider().getX3dModel();
//      System.out.println("X3D model construction complete.");
	
        // next handle command line arguments
        boolean hasArguments = (args != null) &amp;&amp; (args.length &gt; 0);
        boolean validate = true; // default
        boolean argumentsLoadNewModel = false;
        String  fileName = new String();

        if (args != null)
        {
                for (String arg : args)
                {
                        if (arg.toLowerCase().startsWith("-v") || arg.toLowerCase().contains("validate"))
                        {
                                validate = true; // making sure
                        }
                        if (arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_X3D) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_CLASSICVRML) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_X3DB) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_VRML97) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_EXI) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_GZIP) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_ZIP) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_HTML) ||
                                arg.toLowerCase().endsWith(X3D.FILE_EXTENSION_XHTML))
                        {
                                argumentsLoadNewModel = true;
                                fileName = arg;
                        }
                }
        }
        if      (argumentsLoadNewModel)
                System.out.println("WARNING: \"Basic.Followers.Slider\" model invocation is attempting to load file \"" + fileName + "\" instead of simply validating itself... file loading ignored.");
        else if (hasArguments) // if no arguments provided, this method produces usage warning
                thisExampleX3dModel.handleArguments(args);
	
        if (validate)
        {
            //  System.out.println("--- TODO fix duplicated outputs ---"); // omit when duplicated outputs problem is solved/refactored
		String validationResults = thisExampleX3dModel.validationReport();
            //  System.out.println("-----------------------------------"); // omit when duplicated outputs problem is solved/refactored
                System.out.print("Basic.Followers.Slider self-validation test confirmation: ");
                if (!validationResults.equals("success"))
                    System.out.println();
                System.out.println(validationResults.trim());

                // experimental: test X3DJSAIL output files
                // Followers/Slider_JavaExport.* file validation is checked when building X3D Example Archives
                String filenameX3D  = "Followers/Slider_JavaExport.x3d"; 
                String filenameX3DV = "Followers/Slider_JavaExport.x3dv"; 
                String filenameJSON = "Followers/Slider_JavaExport.json";
                thisExampleX3dModel.toFileX3D        (filenameX3D);
                thisExampleX3dModel.toFileClassicVRML(filenameX3DV);
// TODO         thisExampleX3dModel.toFileJSON       (filenameJSON);
        }
    }
}
</pre></body></html>