<?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 content='AcousticTransmissionCylinderPrototype.x3d' name='title'/>
    <meta content='An acoustic transmission cylinder has a moving inner radius and a constant (maximum) outer radius, visualizing the pulse width of cylindrical propagation.' name='description'/>
    <meta content='Don Brutzman and Oliver Tan' name='creator'/>
    <meta content='11 May 2004' name='created'/>
    <meta content='20 October 2019' name='modified'/>
    <meta content='Acoustic transmission' name='subject'/>
    <meta content='https://www.web3d.org/x3d/content/examples/Savage/CommunicationsAndSensors/SeaWeb/AcousticTransmissionCylinderPrototype.x3d' name='identifier'/>
    <meta content='X3D-Edit 3.2, https://www.web3d.org/x3d/tools/X3D-Edit' name='generator'/>
    <meta content='../../license.html' name='license'/>
  </head>
  <Scene>
    <ProtoDeclare appinfo='AcousticTransmissionCylinder visualizes the pulse width of cylindrical propagation with has a receding inner radius and a (maximum outer radius .' name='AcousticTransmissionCylinder'>
      <ProtoInterface>
        <field accessType='inputOnly' appinfo='Upon receipt of a boolean true event start a single (not continuous) transmission' name='startTransmission' type='SFBool'/>
        <field accessType='inputOnly' appinfo='Upon receipt of a boolean true event start continuous transmissions' name='startContinuousTransmissions' type='SFBool'/>
        <field accessType='inputOnly' appinfo='Propagation range in meters' name='set_range' type='SFFloat'/>
        <field accessType='initializeOnly' appinfo='Default propagation range in meters' name='defaultRange' type='SFFloat' value='2'/>
        <field accessType='initializeOnly' appinfo='Speed in meters / second' name='transmissionPropagationSpeed' type='SFFloat' value='1500'/>
        <field accessType='inputOnly' appinfo='Duration in seconds' name='set_transmissionDuration' type='SFFloat'/>
        <field accessType='initializeOnly' appinfo='Duration in seconds' name='transmissionDuration' type='SFFloat' value='5'/>
        <field accessType='inputOnly' appinfo='Number of segmented sections in 360-degree cylindrical beam' name='set_beamCount' type='SFInt32'/>
        <field accessType='initializeOnly' appinfo='number of segmented sections in 360-degree cylindrical beam' name='beamCount' type='SFInt32' value='0'/>
        <field accessType='initializeOnly' appinfo='Height of cylinder in meters' name='height' type='SFFloat' value='2'/>
        <field accessType='inputOnly' appinfo='Color of cylinder' name='set_color' type='SFColor'/>
        <field accessType='initializeOnly' appinfo='Default color of cylinder' name='color' type='SFColor' value='1 1 0.2'/>
        <field accessType='initializeOnly' name='traceEnabled' type='SFBool' value='false'/>
      </ProtoInterface>
      <ProtoBody>
        <Group>
          <Shape>
            <Extrusion DEF='TransmissionProfile' beginCap='false' convex='false' creaseAngle='3.14' endCap='false'/>
            <Appearance>
              <Material DEF='TransmissionProfileMaterial'/>
            </Appearance>
          </Shape>
          <TimeSensor DEF='AnimationClock'/>
          <TimeSensor DEF='RestartClock'/>
          <ROUTE fromField='cycleTime' fromNode='RestartClock' toField='set_startTime' toNode='AnimationClock'/>
          <Script DEF='TransmissionPropagationScript' directOutput='true'>
            <field accessType='inputOnly' name='startTransmission' type='SFBool'/>
            <field accessType='inputOnly' name='startContinuousTransmissions' type='SFBool'/>
            <field accessType='inputOnly' name='set_range' type='SFFloat'/>
            <field accessType='initializeOnly' name='defaultRange' type='SFFloat'/>
            <field accessType='initializeOnly' name='transmissionPropagationSpeed' type='SFFloat'/>
            <field accessType='inputOnly' appinfo='Duration in seconds' name='set_transmissionDuration' type='SFFloat'/>
            <field accessType='initializeOnly' appinfo='Duration in seconds' name='transmissionDuration' type='SFFloat'/>
            <field accessType='initializeOnly' name='outerRadius' type='SFFloat' value='0'/>
            <field accessType='initializeOnly' name='innerRadius' type='SFFloat' value='0'/>
            <field accessType='initializeOnly' name='height' type='SFFloat'/>
            <field accessType='inputOnly' name='set_fraction' type='SFFloat'/>
            <field accessType='outputOnly' name='animationDuration' type='SFTime'/>
            <field accessType='outputOnly' name='restartClockDuration' type='SFTime'/>
            <field accessType='outputOnly' name='loopAnimation' type='SFBool'/>
            <field accessType='initializeOnly' name='position' type='MFVec2f'>
              <!-- no initialization value, use default -->
            </field>
            <field accessType='inputOnly' appinfo='Number of segmented sections in 360-degree cylindrical beam' name='set_beamCount' type='SFInt32'/>
            <field accessType='initializeOnly' appinfo='number of segmented sections in 360-degree cylindrical beam' name='beamCount' type='SFInt32'/>
            <field accessType='initializeOnly' appinfo='holding variable for intermediate computations' name='newSpine' type='MFVec3f'/>
            <field accessType='initializeOnly' appinfo='horizontal circular spine along central perimeter of rectangular transmission boundaries for each beam' name='spine' type='MFVec3f' value='1.00 0.00 0.00 0.92 0.00 -0.38 0.71 0.00 -0.71 0.38 0.00 -0.92 0.00 0.00 -1.00 -0.38 0.00 -0.92 -0.71 0.00 -0.71 -0.92 0.00 -0.38 -1.00 0.00 -0.00 -0.92 0.00 0.38 -0.71 0.00 0.71 -0.38 0.00 0.92 0.00 0.00 1.00 0.38 0.00 0.92 0.71 0.00 0.71 0.92 0.00 0.38 1.00 0.00 0.00'/>
            <field accessType='initializeOnly' appinfo='vertical rectangular outline from inner radius to outer radius' name='crossSection' type='MFVec2f'>
              <!-- no initialization value, use default -->
            </field>
            <field accessType='inputOnly' name='set_color' type='SFColor'/>
            <field accessType='initializeOnly' name='color' type='SFColor'/>
            <field accessType='initializeOnly' name='transparency' type='SFFloat' value='0'/>
            <field accessType='outputOnly' name='animationStartTime' type='SFTime'/>
            <field accessType='outputOnly' name='loopStartTime' type='SFTime'/>
            <field accessType='outputOnly' name='crossSection_changed' type='MFVec2f'/>
            <field accessType='outputOnly' name='spine_changed' type='MFVec3f'/>
            <field accessType='outputOnly' name='transparency_changed' type='SFFloat'/>
            <field accessType='initializeOnly' name='signalProfileMaterial' type='SFNode'>
              <Material USE='TransmissionProfileMaterial'/>
            </field>
            <field accessType='initializeOnly' name='traceEnabled' type='SFBool'/>
            <IS>
              <connect nodeField='startTransmission' protoField='startTransmission'/>
              <connect nodeField='startContinuousTransmissions' protoField='startContinuousTransmissions'/>
              <connect nodeField='set_range' protoField='set_range'/>
              <connect nodeField='defaultRange' protoField='defaultRange'/>
              <connect nodeField='transmissionPropagationSpeed' protoField='transmissionPropagationSpeed'/>
              <connect nodeField='set_transmissionDuration' protoField='set_transmissionDuration'/>
              <connect nodeField='transmissionDuration' protoField='transmissionDuration'/>
              <connect nodeField='set_beamCount' protoField='set_beamCount'/>
              <connect nodeField='beamCount' protoField='beamCount'/>
              <connect nodeField='height' protoField='height'/>
              <connect nodeField='set_color' protoField='set_color'/>
              <connect nodeField='color' protoField='color'/>
              <connect nodeField='traceEnabled' protoField='traceEnabled'/>
            </IS>
            <![CDATA[
ecmascript:

function initialize()
{
	outerRadius = -1.0;
	innerRadius = -1.0;

	animationDuration = defaultRange / transmissionPropagationSpeed + transmissionDuration;

	tracePrint('beamCount = ' + beamCount);
	tracePrint('defaultRange = ' + defaultRange);
	tracePrint('animationDuration=' + animationDuration);
	tracePrint('transmissionPropagationSpeed=' + transmissionPropagationSpeed);

	computeSpine(beamCount);

    updateCrossSection(0);

	updateExtrusionShape(crossSection, spine, color);
}
function updateRadii(fraction)
{
	_transmissionPropagationDuration = defaultRange / transmissionPropagationSpeed;
	_animationDuration = _transmissionPropagationDuration + transmissionDuration;
	_spineRadius = 1;
	
	outerRadius = fraction * _animationDuration * transmissionPropagationSpeed - _spineRadius;

	if (outerRadius > (defaultRange - _spineRadius)) {
		outerRadius = defaultRange - _spineRadius;
	}

	if ((fraction * _animationDuration) > (_transmissionPropagationDuration + transmissionDuration * 7/8)) 
	{
		transparency_changed = ( (fraction * _animationDuration) - (_transmissionPropagationDuration + transmissionDuration * 7/8) ) / (transmissionDuration * 1/8);
	}

	if ((fraction * _animationDuration) <= transmissionDuration)
	{
		innerRadius = -_spineRadius;
	} else {
		innerRadius = ((fraction * _animationDuration) - transmissionDuration) * transmissionPropagationSpeed - _spineRadius;
		if (innerRadius > defaultRange) {
			innerRadius = defaultRange;
		}
	}

	tracePrint('fraction = ' + fraction);
	tracePrint('outerRadius = ' + outerRadius);
	tracePrint('innerRadius = ' + innerRadius);
}
function set_beamCount (beamCount)
{
    alwaysPrint('set_beamCount(' + beamCount + '), beam spacing=' + (360/beamCount) + ' degrees');
    computeSpine(beamCount);
}
function computeSpine (beamCount)
{
	if (beamCount < 3)
    {
        alwaysPrint('** insufficient beamCount=' + beamCount + ', ignored, spine not recomputed');
        return;
    }
    newSpine = new MFVec3f ();
    for (index = 0; index <= beamCount; index++)
	{
		angle = 2.0 * Math.PI * index / beamCount;
        newSpine[index] = new SFVec3f (Math.sin(angle), 0.0, Math.cos(angle));
	}
    newSpine[beamCount] = newSpine[0]; // ensure beginning point matches end point
    spine = newSpine;
	tracePrint('spine.length=' + spine.length + ', spine=' + spine);
}
function updateCrossSection(fraction)
{
	updateRadii(fraction);

	_spineRadius = 1;
	_outerHeight = Math.abs((outerRadius + _spineRadius) * Math.tan(Math.PI/6));

	if (_outerHeight > height)
	{
		_outerHeight = height;
	}

	_innerHeight = Math.abs((innerRadius + _spineRadius) * Math.tan(Math.PI/6));

	if (_innerHeight > height)
	{
		_innerHeight = height;
	}

	index = 0;
	position[index]     = new SFVec2f(outerRadius, _outerHeight/2);
	crossSection[index] = new SFVec2f(position[index].x, position[index].y);
	index++;
	
	position[index]     = new SFVec2f(innerRadius, _innerHeight/2);
	crossSection[index] = new SFVec2f(position[index].x, position[index].y);
	index++;

	position[index]     = new SFVec2f(innerRadius, -_innerHeight/2);
	crossSection[index] = new SFVec2f(position[index].x, position[index].y);
	index++;

	position[index]     = new SFVec2f(outerRadius, -_outerHeight/2);
	crossSection[index] = new SFVec2f(position[index].x, position[index].y);
	index++;

	position[index]     = new SFVec2f(outerRadius, _outerHeight/2);
	crossSection[index] = new SFVec2f(position[index].x, position[index].y);
	
	tracePrint('position     = ' + position);
	tracePrint('crossSection = ' + crossSection);
}
function startTransmission(value, timeStamp)
{
	if (value == true)
	{
		loopAnimation = false;
		loopStartTime = -1;
		animationStartTime = timeStamp;
		tracePrint('startTransmission ()');
	}
}
function startContinuousTransmissions(value, timeStamp)
{
	if (value == true)
	{
		loopAnimation = true;
		loopStartTime = timeStamp;
		animationStartTime = timeStamp;
		tracePrint('startContinuousTransmissions ()');
	}
}
function set_range(value, timeStamp)
{
	if (value >= 0)
	{
		defaultRange = value;
		tracePrint('defaultRange = ' + defaultRange);
	}
	else tracePrint('set_range (' + value + '); // no response, negative');
}
function set_color(value, timeStamp)
{
	color = value;
	tracePrint('color = ' + color);
}
function set_transmissionDuration(value, timeStamp)
{
	if (value >= 0) 
	{
		transmissionDuration = value;
		animationDuration = defaultRange / transmissionPropagationSpeed + transmissionDuration;
		restartClockDuration = 2 * animationDuration;
		tracePrint('transmissionDuration = ' + transmissionDuration);
		tracePrint('animationDuration    = ' + animationDuration);
		tracePrint('restartClockDuration = ' + restartClockDuration);
	}
	else tracePrint('set_transmissionDuration (' + value + '); // no response, negative');
}
function set_fraction(value, timeStamp)
{
	updateCrossSection(value);

	updateExtrusionShape(crossSection, spine, color);
}
function updateExtrusionShape(crossSection, spine, color)
{
	// emissiveColor appears unaffected by transparency, unfortunately
	signalProfileMaterial.diffuseColor = color;
	signalProfileMaterial.transparency = transparency;

	tracePrint('Updating crossSection:');
	tracePrint('  crossSection = ' + crossSection);
	tracePrint('  spine = ' + spine);
	tracePrint('  transparency = ' + transparency);

	crossSection_changed = crossSection;
	spine_changed = spine;
}
function tracePrint(value)
{
  if (traceEnabled) alwaysPrint (value);
}
function alwaysPrint(value)
{
	Browser.println ('[AcousticTransmissionCylinderPrototype] ' + value);
}
]]>
          </Script>
          <ROUTE fromField='fraction_changed' fromNode='AnimationClock' toField='set_fraction' toNode='TransmissionPropagationScript'/>
          <ROUTE fromField='crossSection_changed' fromNode='TransmissionPropagationScript' toField='set_crossSection' toNode='TransmissionProfile'/>
          <ROUTE fromField='spine_changed' fromNode='TransmissionPropagationScript' toField='set_spine' toNode='TransmissionProfile'/>
          <ROUTE fromField='transparency_changed' fromNode='TransmissionPropagationScript' toField='transparency' toNode='TransmissionProfileMaterial'/>
          <ROUTE fromField='animationDuration' fromNode='TransmissionPropagationScript' toField='set_cycleInterval' toNode='AnimationClock'/>
          <ROUTE fromField='restartClockDuration' fromNode='TransmissionPropagationScript' toField='set_cycleInterval' toNode='RestartClock'/>
          <ROUTE fromField='loopAnimation' fromNode='TransmissionPropagationScript' toField='loop' toNode='RestartClock'/>
          <ROUTE fromField='animationStartTime' fromNode='TransmissionPropagationScript' toField='set_startTime' toNode='AnimationClock'/>
          <ROUTE fromField='loopStartTime' fromNode='TransmissionPropagationScript' toField='set_startTime' toNode='RestartClock'/>
        </Group>
      </ProtoBody>
    </ProtoDeclare>
    <!-- Viewable geometry for this scene is anchored text that links to an example showing ExternProtoDeclare usage of AcousticTransmissionCylinder -->
    <WorldInfo info='"Produce acoustic transmission cylinders"' title='AcousticTransmissionCylinderPrototype'/>
    <Viewpoint description='Acoustic Transmission Cylinder' position='0 0 15'/>
    <Anchor description='Acoustic Transmission Cylinder Example' url='"AcousticTransmissionCylinderExample.x3d" "../../CommunicationsAndSensors/SeaWeb/AcousticTransmissionCylinderExample.x3d" "https://www.web3d.org/x3d/content/examples/Savage/CommunicationsAndSensors/SeaWeb/AcousticTransmissionCylinderExample.x3d" "AcousticTransmissionCylinderExample.wrl" "../../CommunicationsAndSensors/SeaWeb/AcousticTransmissionCylinderExample.wrl" "https://www.web3d.org/x3d/content/examples/Savage/CommunicationsAndSensors/SeaWeb/AcousticTransmissionCylinderExample.wrl"'>
      <Shape>
        <Appearance>
          <Material diffuseColor='0 1 1' emissiveColor='0 1 1'/>
        </Appearance>
        <Text string='"AcousticTransmissionCylinderPrototype" "is a Prototype definition file" "" "To see an example scene" "click this text and view" "AcousticTransmissionCylinderExample"'>
          <FontStyle justify='"MIDDLE" "MIDDLE"'/>
        </Text>
      </Shape>
    </Anchor>
  </Scene>
</X3D>