X3D Model Documentation: BathymetryGeneratorViaExtrusionPrototype.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=' BathymetryGeneratorViaExtrusionPrototype.x3d '/>
  6            <meta name='descriptioncontent='This prototype generates bathymetry based on the input data, and uses Extrusion as the output geometry (with some problems as a result).'/>
  7            <meta name='creatorcontent='Jane Wu'/>
  8            <meta name='createdcontent='8 January 2002'/>
  9            <meta name='modifiedcontent='28 November 2019'/>
 10            <meta name='subjectcontent='bathymetry'/>
 11            <meta name='referencecontent='https://www.web3d.org/technicalinfo/specifications/vrml97/part1/nodesRef.html#Extrusion'/>
 12            <meta name='identifiercontent=' https://www.web3d.org/x3d/content/examples/Savage/Tools/Animation/BathymetryGeneratorViaExtrusionPrototype.x3d '/>
 13            <meta name='generatorcontent='X3D-Edit 3.2, https://www.web3d.org/x3d/tools/X3D-Edit'/>
 14            <meta name='licensecontent='../../license.html'/>
 15       </head>
<!--

<!--
Event Graph ROUTE Table shows event connections.
-->
<!-- to top DEF nodes index: Bathymetry, BathymetryScript

Index for Viewpoint node: Viewpoint_1

Index for ProtoDeclare definition: BathymetryGenerator
-->
 16       <Scene>
 17            <WorldInfo title='BathymetryGeneratorViaExtrusionPrototype.x3d'/>
 18            <ProtoDeclare name='BathymetryGenerator'>
 19                 <ProtoInterface>
 20                      <field name='positionArraytype='MFVec3fvalue='0 0 0 10 -4 0 25 -6 0 30 -8 5 38 -15 5 45 -18 5 55 -22 5 60 -25 15 60 -27 22 55 -30 35 48 -35 35 35 -35 35 25 -45 35 20 -55 35 15 -70 35 3 -70 35 -5 -72 40 -5 -75 50 0 -80 55 15 -75 55 30 -70 55 35 -60 55 40 -50 55 50 -34 55 65 -23 70accessType='initializeOnly'/>
 21                      <field name='timeArraytype='MFTimevalue='1 3 6 8 10 12 14 15 17 18 23 28 35 37 39 43 45 47 48 53 58 60 61 65 70accessType='initializeOnly'
                     appinfo='for future development'/>
 22                      <field name='colorSchemeDepthRangeArraytype='MFVec2fvalue='0 -10 -10 -20 -20 -30 -30 -40 -40 -50 -50 -60 -60 -70 -70 -999999accessType='initializeOnly'/>
 23                      <field name='colorSchemeColorArraytype='MFColorvalue='1 1 0.2 0.6 1 1 0 1 1 0.2 0.6 0.2 1 0 1 0.56 0 0.32 0.2 0.3 0.7 0 0 1accessType='initializeOnly'/>
 24                      <field name='beamWidthtype='SFFloatvalue='2accessType='initializeOnly'/>
 25                      <field name='surfaceTransparencytype='SFFloatvalue='0.25accessType='initializeOnly'/>
 26                      <field name='traceEnabledtype='SFBoolvalue='falseaccessType='initializeOnly'/>
 27                 </ProtoInterface>
 28                 <ProtoBody>
 29                      <Group>
 30 
                         <!-- ROUTE information for Bathymetry node:  [from BathymetryScript.bathyNodes to addChildren ] -->
                         <Transform DEF='Bathymetry'/>
 31 
                         <!-- ROUTE information for BathymetryScript node:  [from bathyNodes to Bathymetry.addChildren ] -->
                         <Script DEF='BathymetryScriptdirectOutput='true'>
 32                                <field name='positionArraytype='MFVec3faccessType='initializeOnly'/>
 33                                <field name='timeArraytype='MFTimeaccessType='initializeOnly'/>
 34                                <field name='colorSchemeDepthRangeArraytype='MFVec2faccessType='initializeOnly'/>
 35                                <field name='colorSchemeColorArraytype='MFColoraccessType='initializeOnly'/>
 36                                <field name='beamWidthtype='SFFloataccessType='initializeOnly'/>
 37                                <field name='transparencytype='SFFloataccessType='initializeOnly'/>
 38                                <field name='spinetype='MFVec3fvalue='0 0 0 0 1 0accessType='initializeOnly'/>
 39                                <field name='scaletype='MFVec2fvalue='1 1accessType='initializeOnly'/>
 40                                <field name='orientationtype='MFRotationvalue='0 0 1 0accessType='initializeOnly'/>
 41                                <field name='bathyColortype='SFColorvalue='1 1 1accessType='initializeOnly'/>
 42                                <field name='bathyNodestype='MFNodeaccessType='outputOnly'/>
 43                                <field name='traceEnabledtype='SFBoolaccessType='initializeOnly'/>
 44                                <field name='coordinatetype='SFVec3fvalue='0 0 0accessType='initializeOnly'/>
 45                                <field name='previousPositiontype='SFVec3fvalue='0 0 0accessType='initializeOnly'/>
 46                                <field name='positiontype='SFVec3fvalue='0 0 0accessType='initializeOnly'/>
 47                                <field name='bathyNodeIndextype='SFInt32value='0accessType='initializeOnly'/>
 48                                <IS>
 49                                     <connect nodeField='positionArrayprotoField='positionArray'/>
 50                                     <connect nodeField='timeArrayprotoField='timeArray'/>
 51                                     <connect nodeField='colorSchemeDepthRangeArrayprotoField='colorSchemeDepthRangeArray'/>
 52                                     <connect nodeField='colorSchemeColorArrayprotoField='colorSchemeColorArray'/>
 53                                     <connect nodeField='beamWidthprotoField='beamWidth'/>
 54                                     <connect nodeField='transparencyprotoField='surfaceTransparency'/>
 55                                     <connect nodeField='traceEnabledprotoField='traceEnabled'/>
 56                                </IS>
  <![CDATA[
            
ecmascript:

function initialize()
{
	bathyNodeIndex = 0;

	spineIndex = 0;
	position = positionArray[0];
	spine[spineIndex] = new SFVec3f(position.x, 0, position.z);
	scale[spineIndex] = new SFVec2f(1, Math.abs(position.y));
	spineIndex++;

	previousPosition = new SFVec3f(position.x, position.y, position.z);
	//Determine the initial depth range
	for (j = 0; j < colorSchemeDepthRangeArray.length; j++)
	{
		if (position.y >= colorSchemeDepthRangeArray[j].y)
			break;
	}
	currentDepthRangeIndex = j;

	for (i = 1; i < positionArray.length; i++)
	{			
		if (previousPosition.y == colorSchemeDepthRangeArray[currentDepthRangeIndex].y &&
		    positionArray[i].y != colorSchemeDepthRangeArray[currentDepthRangeIndex].y)
			terminateExtrusionSegmentWithCurrentPosition(currentDepthRangeIndex);

		//Update new position
		position = positionArray[i];

		//Determine the correct depth range
		if (position.y <= previousPosition.y)
		{
			for (j = currentDepthRangeIndex; j < colorSchemeDepthRangeArray.length; j++)
			{
				if (position.y >= colorSchemeDepthRangeArray[j].y)
					break;

				if (previousPosition.y != colorSchemeDepthRangeArray[currentDepthRangeIndex].y)
					terminateExtrusionSegmentWithDepthRangeBoundary(currentDepthRangeIndex);
			}
			currentDepthRangeIndex = j;
		}
		else
		{
			for (j = currentDepthRangeIndex; j > -1; j--)
			{
				if (position.y < colorSchemeDepthRangeArray[j-1].y)
					break;

				if (position.y > colorSchemeDepthRangeArray[j-1].y)
					terminateExtrusionSegmentWithDepthRangeBoundary(j-1);
			}
			currentDepthRangeIndex = j;
		}

		spine[spineIndex] = new SFVec3f(position.x, 0, position.z);
		scale[spineIndex] = new SFVec2f(1, Math.abs(position.y));
		spineIndex++;

		previousPosition = new SFVec3f(position.x, position.y, position.z);
	}
	terminateExtrusionSegmentWithCurrentPosition(currentDepthRangeIndex);
}

function terminateExtrusionSegmentWithDepthRangeBoundary(index)
{
	depthRange = colorSchemeDepthRangeArray[index];

	findCoordinate(previousPosition.x, position.x, previousPosition.y, position.y, depthRange.y);
	xPrime = coordinate;
	findCoordinate(previousPosition.z, position.z, previousPosition.y, position.y, depthRange.y);
	zPrime = coordinate;
	spine[spineIndex] = new SFVec3f(xPrime, 0, zPrime);
	scale[spineIndex] = new SFVec2f(1, Math.abs(depthRange.y));

	if (scale[scale.length-2].y > scale[scale.length-1].y)
		color = colorSchemeColorArray[index+1];
	else
		color = colorSchemeColorArray[index];

	createExtrusionShape(spine, scale, color);

	//Reset values to start the next extrustion segment
	spineIndex = 0;
	resetSpine();
	resetScale();

	//Update the current segment end as the start of the next segment
	spine[spineIndex] = new SFVec3f(xPrime, 0, zPrime);
	scale[spineIndex] = new SFVec2f(1, Math.abs(depthRange.y));
	spineIndex++;	
}

function terminateExtrusionSegmentWithCurrentPosition(index)
{
	if (scale[scale.length-1].y != Math.abs(colorSchemeDepthRangeArray[index].y))
		index--;

	if (scale[scale.length-2].y > scale[scale.length-1].y)
		color = colorSchemeColorArray[index+1];
	else
		color = colorSchemeColorArray[index];

	createExtrusionShape(spine, scale, color);

	//Reset values to start the next extrustion segment
	spineIndex = 0;
	resetSpine();
	resetScale();

	//Update the current segment end as the start of the next segment
	spine[spineIndex] = new SFVec3f(position.x, 0, position.z);
	scale[spineIndex] = new SFVec2f(1, Math.abs(position.y));
	spineIndex++;

	//Update the previousPosition
	previousPosition = new SFVec3f(position.x, position.y, position.z);
}

function findCoordinate(x1, x2, y1, y2, yPrime)
{
	coordinate = ((x1 - x2) / (y1 - y2)) * yPrime + ((x2*y1 - x1*y2) / (y1 - y2));
}

function createExtrusionShape(spine, scale, color)
{
	determineOrientation(spine);
	tracePrint('An extrusion is created whose spine is: ' + spine);
	tracePrint('and scale is: ' + scale);
	tracePrint('orientation is: ' + orientation);
	tracePrint('color is: ' + color);
	alwaysPrint('number of spine points is: ' + spine.length);
	alwaysPrint('orientation is: ' + orientation);

	//Build the VRML string
	extrusionSyntax  = 'Shape {\n';
	extrusionSyntax += '   appearance Appearance {' + '\n';
	extrusionSyntax += '      material Material {' + '\n';
	extrusionSyntax += '         diffuseColor ' + color + '\n';
	extrusionSyntax += '         transparency ' + transparency + '\n';
	extrusionSyntax += '      }' + '\n';
	extrusionSyntax += '   }' + '\n';
	extrusionSyntax += '   geometry Extrusion {' + '\n';
	extrusionSyntax += '      crossSection [' + (beamWidth/(-2)) + ', 1, ' + (beamWidth/2) + ', 1, ' + (beamWidth/(-2)) + ', 1]' + '\n';
	extrusionSyntax += '      scale ' + scale + '\n';
	extrusionSyntax += '      spine ' + spine + '\n';
	extrusionSyntax += '      orientation ' + orientation + '\n';
	extrusionSyntax += '      creaseAngle 1.57' + '\n';
	extrusionSyntax += '   }' + '\n';
	extrusionSyntax += '}';

	//Create Extrusion shape
	tracePrint (extrusionSyntax);
	bathySegment = new SFNode(extrusionSyntax);

	bathyNodes[bathyNodeIndex] = bathySegment;
	bathyNodeIndex++;
}

function determineOrientation(spine)
{
   previousZAxis = null;
   orientation = new MFRotation();
   //Special cases
   if (spine.length == 2)
   {
      if (spine[0].z == spine[1].z)
      {
         if (spine[0].x <= spine[1].x) //positive x direction
            orientation[0] = orientation[1] = new SFRotation(0, 1, 0, 1.57);
         else //negative x direction
            orientation[0] = orientation[1] = new SFRotation(0, 1, 0, -1.57);
      }
      else
      {
         if (spine[0].x == spine[1].x) //parallet to the z axis
            orientation[0] = orientation[1] = new SFRotation(0, 1, 0, 0);
         else
         {
            angleRadian = Math.atan((spine[0].x- spine[1].x) / (spine[0].z - spine[1].z));
//          angleRadian = Math.atan2((spine[0].x- spine[1].x), (spine[0].z - spine[1].z));
            
            orientation[0] = orientation[1] = new SFRotation(0, 1, 0, angleRadian);
         }
      }
      return;
   }

   for (n = 0; n < spine.length; n++)
   {
      //If spine is not closed, the Z axis used for the first spine point is the same as the Z axis for spine[1].
      //The Z axis used for the last spine point is the same as the Z axis for spine[spine.length - 2].   
      if (n == 0)
         si = 1;
      else if (n == (spine.length - 1))
         si = spine.length - 2;
      else
         si = n;

      zAxis = (spine[si+1].subtract(spine[si])).cross((spine[si-1].subtract(spine[si])));

      while (zAxis.x == 0 && zAxis.y == 0 && zAxis.z == 0)
      {
         if (previousZAxis == null)
         {
            ++si;
            if (si == (spine.length - 1)) //The entire spine is collinear
            {
               zAxis = new SFVec3f(1, 0, 0);
               break;
            }

            zAxis = (spine[si+1].subtract(spine[si])).cross((spine[si-1].subtract(spine[si])));
         }
         else
            zAxis = new SFVec3f(previousZAxis.x, previousZAxis.y, previousZAxis.z);
      }

      adjustedZAxis = zAxis;
      if (n == 0)
         previousZAxis = zAxis;
      else
      {
         dotProduct = zAxis.dot(previousZAxis);
         if (dotProduct < 0)
            adjustedZAxis = new SFVec3f(zAxis.multiply(-1).x, zAxis.multiply(-1).y, zAxis.multiply(-1).z);

         previousZAxis = adjustedZAxis;
      }
      
      zAxisNormalized = adjustedZAxis.normalize();
      theta = Math.acos(zAxisNormalized.dot(new SFVec3f(0, -1, 0)));
      if (spine[1].x < spine[0].x)
         orientation[n] = new SFRotation(0, -1, 0, theta);
      else
         orientation[n] = new SFRotation(0, 1, 0, theta);
   }
if (theta == 0)
   Browser.println ('rotation angle = ' + theta);
else if (theta > 1.57 && theta < 3.14)
   Browser.println ('rotation angle = ' + theta);
else if (theta > 3.14)
   Browser.println ('rotation angle = ' + theta);
}

function resetSpine()
{
	spine = new MFVec3f();
}

function resetScale()
{
	scale = new MFVec2f();
}

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

function alwaysPrint(string)
{
	Browser.println ('[BathymetryGenerator] ' + string);
}

          
]]>
 58                           </Script>
 59                           < ROUTE  fromNode='BathymetryScript' fromField='bathyNodes' toNode='Bathymetry' toField='addChildren'/>
 60                           <Shape>
 61                                <Extrusion/>
 62                           </Shape>
 63                      </Group>
 64                 </ProtoBody>
 65            </ProtoDeclare>
 66            <Viewpoint description='MainViewposition='0 -50 200'/>
 67            <ProtoInstance name='BathymetryGenerator'>
 68                 <fieldValue name='positionArrayvalue='0 0 0 10 -4 0 25 -6 0 30 -8 5 38 -15 5 45 -18 5 55 -22 5 60 -25 15 60 -27 22 55 -30 35 48 -35 35 35 -35 35 25 -45 35 20 -55 35 15 -70 35 3 -70 35 -5 -72 40 -5 -75 50 0 -80 55 15 -75 55 30 -70 55 35 -60 55 40 -50 55 50 -34 55 65 -23 70'/>
 69                 <fieldValue name='surfaceTransparencyvalue='0.25'/>
 70                 <fieldValue name='traceEnabledvalue='true'/>
 71            </ProtoInstance>
 72       </Scene>
 73  </X3D>
<!--

<!--
Event Graph ROUTE Table shows event connections.
-->
<!-- to top DEF nodes index: Bathymetry, BathymetryScript

Index for Viewpoint node: Viewpoint_1

Index for ProtoDeclare definition: BathymetryGenerator
-->
X3D Tooltips element index: connect, Extrusion, field, fieldValue, Group, head, IS, meta, ProtoBody, ProtoDeclare, ProtoInstance, ProtoInterface, ROUTE, Scene, Script, Shape, Transform, Viewpoint, WorldInfo, X3D, plus documentation for accessType definitions, type definitions, XML data types, and field types

Event Graph ROUTE Table with 1 ROUTE connection 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.

BathymetryScript
Script
bathyNodes
MFNode

ROUTE
event to
(1)
Bathymetry
Transform
addChildren
MFNode

line 67
ProtoInstance
BathymetryGenerator
No direct ROUTE connection found for events to/from this node.
This ProtoInstance contains SFNode/MFNode fieldValue declarations with
direct access to other nodes, and thus has potential to produce run-time animation. 

Additional guidance on X3D animation can be found in the 10-Step Animation Design Process and Event Tracing hint sheets. Have fun with X3D! 😀

-->
<!-- Online at
https://www.web3d.org/x3d/content/examples/Savage/Tools/Animation/BathymetryGeneratorViaExtrusionPrototypeIndex.html -->
<!-- Version control at
https://sourceforge.net/p/x3d/code/HEAD/tree/www.web3d.org/x3d/content/examples/Savage/Tools/Animation/BathymetryGeneratorViaExtrusionPrototype.x3d -->

<!-- Color-coding 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)
    <ProtoInstance name='ProtoName'> <field name='fieldName'/> </ProtoInstance> -->

to top <!-- For additional help information about X3D scenes, please see X3D Tooltips, X3D Resources, and X3D Scene Authoring Hints. -->