{ "X3D": {
    "encoding":"UTF-8",
    "@profile":"Immersive",
    "@version":"3.0",
    "@xsd:noNamespaceSchemaLocation":"https://www.web3d.org/specifications/x3d-3.0.xsd",
    "JSON schema":"https://www.web3d.org/specifications/x3d-4.0-JSONSchema.autogenerated.json",
    "head": {
        "meta": [
          {
            "@name":"title",
            "@content":"BathymetryGeneratorViaExtrusionPrototype.x3d"
          },
          {
            "@name":"description",
            "@content":"This prototype generates bathymetry based on the input data, and uses Extrusion as the output geometry (with some problems as a result)."
          },
          {
            "@name":"creator",
            "@content":"Jane Wu"
          },
          {
            "@name":"created",
            "@content":"8 January 2002"
          },
          {
            "@name":"modified",
            "@content":"28 November 2019"
          },
          {
            "@name":"subject",
            "@content":"bathymetry"
          },
          {
            "@name":"reference",
            "@content":"https://www.web3d.org/technicalinfo/specifications/vrml97/part1/nodesRef.html#Extrusion"
          },
          {
            "@name":"identifier",
            "@content":"https://www.web3d.org/x3d/content/examples/Savage/Tools/Animation/BathymetryGeneratorViaExtrusionPrototype.x3d"
          },
          {
            "@name":"generator",
            "@content":"X3D-Edit 3.2, https://www.web3d.org/x3d/tools/X3D-Edit"
          },
          {
            "@name":"license",
            "@content":"../../license.html"
          },
          {
            "@name":"translated",
            "@content":"26 March 2026"
          },
          {
            "@name":"generator",
            "@content":"X3dToJson.xslt, https://www.web3d.org/x3d/stylesheets/X3dToJson.html"
          },
          {
            "@name":"reference",
            "@content":"X3D JSON encoding: https://www.web3d.org/wiki/index.php/X3D_JSON_Encoding"
          }
        ]
    },
    "Scene": {
        "-children":[
          { "WorldInfo":
            {
              "@title":"BathymetryGeneratorViaExtrusionPrototype.x3d"
            }
          },
          { "ProtoDeclare":
            {
              "@name":"BathymetryGenerator",
              "ProtoInterface": {
                  "field": [
                    {
                      "@name":"positionArray",
                      "@accessType":"initializeOnly",
                      "@type":"MFVec3f",
                      "@value":[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]
                    },
                    {
                      "@name":"timeArray",
                      "@accessType":"initializeOnly",
                      "@appinfo":"for future development",
                      "@type":"MFTime",
                      "@value":[1,3,6,8,10,12,14,15,17,18,23,28,35,37,39,43,45,47,48,53,58,60,61,65,70]
                    },
                    {
                      "@name":"colorSchemeDepthRangeArray",
                      "@accessType":"initializeOnly",
                      "@type":"MFVec2f",
                      "@value":[0,-10,-10,-20,-20,-30,-30,-40,-40,-50,-50,-60,-60,-70,-70,-999999]
                    },
                    {
                      "@name":"colorSchemeColorArray",
                      "@accessType":"initializeOnly",
                      "@type":"MFColor",
                      "@value":[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,1]
                    },
                    {
                      "@name":"beamWidth",
                      "@accessType":"initializeOnly",
                      "@type":"SFFloat",
                      "@value":2
                    },
                    {
                      "@name":"surfaceTransparency",
                      "@accessType":"initializeOnly",
                      "@type":"SFFloat",
                      "@value":0.25
                    },
                    {
                      "@name":"traceEnabled",
                      "@accessType":"initializeOnly",
                      "@type":"SFBool",
                      "@value":false
                    }
                  ]
              },
              "ProtoBody": {
                  "-children":[
                    { "Group":
                      {
                        "-children":[
                          { "Transform":
                            {
                              "@DEF":"Bathymetry"
                            }
                          },
                          { "Script":
                            {
                              "@DEF":"BathymetryScript",
                              "@directOutput":true,
                              "field": [
                                {
                                  "@name":"positionArray",
                                  "@accessType":"initializeOnly",
                                  "@type":"MFVec3f"
                                },
                                {
                                  "@name":"timeArray",
                                  "@accessType":"initializeOnly",
                                  "@type":"MFTime"
                                },
                                {
                                  "@name":"colorSchemeDepthRangeArray",
                                  "@accessType":"initializeOnly",
                                  "@type":"MFVec2f"
                                },
                                {
                                  "@name":"colorSchemeColorArray",
                                  "@accessType":"initializeOnly",
                                  "@type":"MFColor"
                                },
                                {
                                  "@name":"beamWidth",
                                  "@accessType":"initializeOnly",
                                  "@type":"SFFloat"
                                },
                                {
                                  "@name":"transparency",
                                  "@accessType":"initializeOnly",
                                  "@type":"SFFloat"
                                },
                                {
                                  "@name":"spine",
                                  "@accessType":"initializeOnly",
                                  "@type":"MFVec3f",
                                  "@value":[0,0,0,0,1,0]
                                },
                                {
                                  "@name":"scale",
                                  "@accessType":"initializeOnly",
                                  "@type":"MFVec2f",
                                  "@value":[1,1]
                                },
                                {
                                  "@name":"orientation",
                                  "@accessType":"initializeOnly",
                                  "@type":"MFRotation",
                                  "@value":[0,0,1,0]
                                },
                                {
                                  "@name":"bathyColor",
                                  "@accessType":"initializeOnly",
                                  "@type":"SFColor",
                                  "@value":[1,1,1]
                                },
                                {
                                  "@name":"bathyNodes",
                                  "@accessType":"outputOnly",
                                  "@type":"MFNode"
                                },
                                {
                                  "@name":"traceEnabled",
                                  "@accessType":"initializeOnly",
                                  "@type":"SFBool"
                                },
                                {
                                  "@name":"coordinate",
                                  "@accessType":"initializeOnly",
                                  "@type":"SFVec3f",
                                  "@value":[0,0,0]
                                },
                                {
                                  "@name":"previousPosition",
                                  "@accessType":"initializeOnly",
                                  "@type":"SFVec3f",
                                  "@value":[0,0,0]
                                },
                                {
                                  "@name":"position",
                                  "@accessType":"initializeOnly",
                                  "@type":"SFVec3f",
                                  "@value":[0,0,0]
                                },
                                {
                                  "@name":"bathyNodeIndex",
                                  "@accessType":"initializeOnly",
                                  "@type":"SFInt32",
                                  "@value":0
                                }
                              ],
                              "IS": {
                                  "connect": [
                                    {
                                      "@nodeField":"positionArray",
                                      "@protoField":"positionArray"
                                    },
                                    {
                                      "@nodeField":"timeArray",
                                      "@protoField":"timeArray"
                                    },
                                    {
                                      "@nodeField":"colorSchemeDepthRangeArray",
                                      "@protoField":"colorSchemeDepthRangeArray"
                                    },
                                    {
                                      "@nodeField":"colorSchemeColorArray",
                                      "@protoField":"colorSchemeColorArray"
                                    },
                                    {
                                      "@nodeField":"beamWidth",
                                      "@protoField":"beamWidth"
                                    },
                                    {
                                      "@nodeField":"transparency",
                                      "@protoField":"surfaceTransparency"
                                    },
                                    {
                                      "@nodeField":"traceEnabled",
                                      "@protoField":"traceEnabled"
                                    }
                                  ]
                              },
                              "#sourceCode":[
"",
"",
"ecmascript:",
"",
"function initialize()",
"{",
"\tbathyNodeIndex = 0;",
"",
"\tspineIndex = 0;",
"\tposition = positionArray[0];",
"\tspine[spineIndex] = new SFVec3f(position.x, 0, position.z);",
"\tscale[spineIndex] = new SFVec2f(1, Math.abs(position.y));",
"\tspineIndex++;",
"",
"\tpreviousPosition = new SFVec3f(position.x, position.y, position.z);",
"\t//Determine the initial depth range",
"\tfor (j = 0; j < colorSchemeDepthRangeArray.length; j++)",
"\t{",
"\t\tif (position.y >= colorSchemeDepthRangeArray[j].y)",
"\t\t\tbreak;",
"\t}",
"\tcurrentDepthRangeIndex = j;",
"",
"\tfor (i = 1; i < positionArray.length; i++)",
"\t{\t\t\t",
"\t\tif (previousPosition.y == colorSchemeDepthRangeArray[currentDepthRangeIndex].y &&",
"\t\t    positionArray[i].y != colorSchemeDepthRangeArray[currentDepthRangeIndex].y)",
"\t\t\tterminateExtrusionSegmentWithCurrentPosition(currentDepthRangeIndex);",
"",
"\t\t//Update new position",
"\t\tposition = positionArray[i];",
"",
"\t\t//Determine the correct depth range",
"\t\tif (position.y <= previousPosition.y)",
"\t\t{",
"\t\t\tfor (j = currentDepthRangeIndex; j < colorSchemeDepthRangeArray.length; j++)",
"\t\t\t{",
"\t\t\t\tif (position.y >= colorSchemeDepthRangeArray[j].y)",
"\t\t\t\t\tbreak;",
"",
"\t\t\t\tif (previousPosition.y != colorSchemeDepthRangeArray[currentDepthRangeIndex].y)",
"\t\t\t\t\tterminateExtrusionSegmentWithDepthRangeBoundary(currentDepthRangeIndex);",
"\t\t\t}",
"\t\t\tcurrentDepthRangeIndex = j;",
"\t\t}",
"\t\telse",
"\t\t{",
"\t\t\tfor (j = currentDepthRangeIndex; j > -1; j--)",
"\t\t\t{",
"\t\t\t\tif (position.y < colorSchemeDepthRangeArray[j-1].y)",
"\t\t\t\t\tbreak;",
"",
"\t\t\t\tif (position.y > colorSchemeDepthRangeArray[j-1].y)",
"\t\t\t\t\tterminateExtrusionSegmentWithDepthRangeBoundary(j-1);",
"\t\t\t}",
"\t\t\tcurrentDepthRangeIndex = j;",
"\t\t}",
"",
"\t\tspine[spineIndex] = new SFVec3f(position.x, 0, position.z);",
"\t\tscale[spineIndex] = new SFVec2f(1, Math.abs(position.y));",
"\t\tspineIndex++;",
"",
"\t\tpreviousPosition = new SFVec3f(position.x, position.y, position.z);",
"\t}",
"\tterminateExtrusionSegmentWithCurrentPosition(currentDepthRangeIndex);",
"}",
"",
"function terminateExtrusionSegmentWithDepthRangeBoundary(index)",
"{",
"\tdepthRange = colorSchemeDepthRangeArray[index];",
"",
"\tfindCoordinate(previousPosition.x, position.x, previousPosition.y, position.y, depthRange.y);",
"\txPrime = coordinate;",
"\tfindCoordinate(previousPosition.z, position.z, previousPosition.y, position.y, depthRange.y);",
"\tzPrime = coordinate;",
"\tspine[spineIndex] = new SFVec3f(xPrime, 0, zPrime);",
"\tscale[spineIndex] = new SFVec2f(1, Math.abs(depthRange.y));",
"",
"\tif (scale[scale.length-2].y > scale[scale.length-1].y)",
"\t\tcolor = colorSchemeColorArray[index+1];",
"\telse",
"\t\tcolor = colorSchemeColorArray[index];",
"",
"\tcreateExtrusionShape(spine, scale, color);",
"",
"\t//Reset values to start the next extrustion segment",
"\tspineIndex = 0;",
"\tresetSpine();",
"\tresetScale();",
"",
"\t//Update the current segment end as the start of the next segment",
"\tspine[spineIndex] = new SFVec3f(xPrime, 0, zPrime);",
"\tscale[spineIndex] = new SFVec2f(1, Math.abs(depthRange.y));",
"\tspineIndex++;\t",
"}",
"",
"function terminateExtrusionSegmentWithCurrentPosition(index)",
"{",
"\tif (scale[scale.length-1].y != Math.abs(colorSchemeDepthRangeArray[index].y))",
"\t\tindex--;",
"",
"\tif (scale[scale.length-2].y > scale[scale.length-1].y)",
"\t\tcolor = colorSchemeColorArray[index+1];",
"\telse",
"\t\tcolor = colorSchemeColorArray[index];",
"",
"\tcreateExtrusionShape(spine, scale, color);",
"",
"\t//Reset values to start the next extrustion segment",
"\tspineIndex = 0;",
"\tresetSpine();",
"\tresetScale();",
"",
"\t//Update the current segment end as the start of the next segment",
"\tspine[spineIndex] = new SFVec3f(position.x, 0, position.z);",
"\tscale[spineIndex] = new SFVec2f(1, Math.abs(position.y));",
"\tspineIndex++;",
"",
"\t//Update the previousPosition",
"\tpreviousPosition = new SFVec3f(position.x, position.y, position.z);",
"}",
"",
"function findCoordinate(x1, x2, y1, y2, yPrime)",
"{",
"\tcoordinate = ((x1 - x2) / (y1 - y2)) * yPrime + ((x2*y1 - x1*y2) / (y1 - y2));",
"}",
"",
"function createExtrusionShape(spine, scale, color)",
"{",
"\tdetermineOrientation(spine);",
"\ttracePrint('An extrusion is created whose spine is: ' + spine);",
"\ttracePrint('and scale is: ' + scale);",
"\ttracePrint('orientation is: ' + orientation);",
"\ttracePrint('color is: ' + color);",
"\talwaysPrint('number of spine points is: ' + spine.length);",
"\talwaysPrint('orientation is: ' + orientation);",
"",
"\t//Build the VRML string",
"\textrusionSyntax  = 'Shape {\n';",
"\textrusionSyntax += '   appearance Appearance {' + '\n';",
"\textrusionSyntax += '      material Material {' + '\n';",
"\textrusionSyntax += '         diffuseColor ' + color + '\n';",
"\textrusionSyntax += '         transparency ' + transparency + '\n';",
"\textrusionSyntax += '      }' + '\n';",
"\textrusionSyntax += '   }' + '\n';",
"\textrusionSyntax += '   geometry Extrusion {' + '\n';",
"\textrusionSyntax += '      crossSection [' + (beamWidth/(-2)) + ', 1, ' + (beamWidth/2) + ', 1, ' + (beamWidth/(-2)) + ', 1]' + '\n';",
"\textrusionSyntax += '      scale ' + scale + '\n';",
"\textrusionSyntax += '      spine ' + spine + '\n';",
"\textrusionSyntax += '      orientation ' + orientation + '\n';",
"\textrusionSyntax += '      creaseAngle 1.57' + '\n';",
"\textrusionSyntax += '   }' + '\n';",
"\textrusionSyntax += '}';",
"",
"\t//Create Extrusion shape",
"\ttracePrint (extrusionSyntax);",
"\tbathySegment = new SFNode(extrusionSyntax);",
"",
"\tbathyNodes[bathyNodeIndex] = bathySegment;",
"\tbathyNodeIndex++;",
"}",
"",
"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()",
"{",
"\tspine = new MFVec3f();",
"}",
"",
"function resetScale()",
"{",
"\tscale = new MFVec2f();",
"}",
"",
"function tracePrint(string)",
"{",
"\tif (traceEnabled)",
"\t\tBrowser.println ('[BathymetryGenerator] ' + string);",
"}",
"",
"function alwaysPrint(string)",
"{",
"\tBrowser.println ('[BathymetryGenerator] ' + string);",
"}",
"",
""
]
                            }
                          },
                          { "ROUTE":
                            {
                              "@fromField":"bathyNodes",
                              "@fromNode":"BathymetryScript",
                              "@toField":"addChildren",
                              "@toNode":"Bathymetry"
                            }
                          },
                          { "Shape":
                            {
                              "-geometry":
                                { "Extrusion":
                                  {
                                  }
                                }
                            }
                          }
                        ]
                      }
                    }
                  ]
              }
            }
          },
          { "Viewpoint":
            {
              "@description":"MainView",
              "@position":[0,-50,200]
            }
          },
          { "ProtoInstance":
            {
              "@name":"BathymetryGenerator",
              "fieldValue": [
                {
                  "@name":"positionArray",
                  "@value":[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]
                },
                {
                  "@name":"surfaceTransparency",
                  "@value":0.25
                },
                {
                  "@name":"traceEnabled",
                  "@value":true
                }
              ]
            }
          }
        ]
    }
  }
}