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='title' content=' BathymetryGeneratorViaExtrusionPrototype.x3d '/> |
6 | <meta 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).'/> |
7 | <meta name='creator' content='Jane Wu'/> |
8 | <meta name='created' content='8 January 2002'/> |
9 | <meta name='modified' content='28 November 2019'/> |
10 | <meta name='subject' content='bathymetry'/> |
11 | <meta name='reference' content='https://www.web3d.org/technicalinfo/specifications/vrml97/part1/nodesRef.html#Extrusion'/> |
12 | <meta name='identifier' content=' https://www.web3d.org/x3d/content/examples/Savage/Tools/Animation/BathymetryGeneratorViaExtrusionPrototype.x3d '/> |
13 | <meta name='generator' content='X3D-Edit 3.2, https://www.web3d.org/x3d/tools/X3D-Edit'/> |
14 | <meta name='license' content='../../license.html'/> |
15 | </head> |
16 | <Scene> |
17 | <WorldInfo title='BathymetryGeneratorViaExtrusionPrototype.x3d'/> |
18 | <ProtoDeclare name='BathymetryGenerator'> |
19 | <ProtoInterface> |
20 | <field name='positionArray' 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' accessType='initializeOnly'/> |
21 |
<field name='timeArray' 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' accessType='initializeOnly'
appinfo='for future development'/> |
22 | <field name='colorSchemeDepthRangeArray' type='MFVec2f' value='0 -10 -10 -20 -20 -30 -30 -40 -40 -50 -50 -60 -60 -70 -70 -999999' accessType='initializeOnly'/> |
23 | <field name='colorSchemeColorArray' 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' accessType='initializeOnly'/> |
24 | <field name='beamWidth' type='SFFloat' value='2' accessType='initializeOnly'/> |
25 | <field name='surfaceTransparency' type='SFFloat' value='0.25' accessType='initializeOnly'/> |
26 | <field name='traceEnabled' type='SFBool' value='false' accessType='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='BathymetryScript' directOutput='true'> |
32 | <field name='positionArray' type='MFVec3f' accessType='initializeOnly'/> |
33 | <field name='timeArray' type='MFTime' accessType='initializeOnly'/> |
34 | <field name='colorSchemeDepthRangeArray' type='MFVec2f' accessType='initializeOnly'/> |
35 | <field name='colorSchemeColorArray' type='MFColor' accessType='initializeOnly'/> |
36 | <field name='beamWidth' type='SFFloat' accessType='initializeOnly'/> |
37 | <field name='transparency' type='SFFloat' accessType='initializeOnly'/> |
38 | <field name='spine' type='MFVec3f' value='0 0 0 0 1 0' accessType='initializeOnly'/> |
39 | <field name='scale' type='MFVec2f' value='1 1' accessType='initializeOnly'/> |
40 | <field name='orientation' type='MFRotation' value='0 0 1 0' accessType='initializeOnly'/> |
41 | <field name='bathyColor' type='SFColor' value='1 1 1' accessType='initializeOnly'/> |
42 | <field name='bathyNodes' type='MFNode' accessType='outputOnly'/> |
43 | <field name='traceEnabled' type='SFBool' accessType='initializeOnly'/> |
44 | <field name='coordinate' type='SFVec3f' value='0 0 0' accessType='initializeOnly'/> |
45 | <field name='previousPosition' type='SFVec3f' value='0 0 0' accessType='initializeOnly'/> |
46 | <field name='position' type='SFVec3f' value='0 0 0' accessType='initializeOnly'/> |
47 | <field name='bathyNodeIndex' type='SFInt32' value='0' accessType='initializeOnly'/> |
48 | <IS> |
49 | <connect nodeField='positionArray' protoField='positionArray'/> |
50 | <connect nodeField='timeArray' protoField='timeArray'/> |
51 | <connect nodeField='colorSchemeDepthRangeArray' protoField='colorSchemeDepthRangeArray'/> |
52 | <connect nodeField='colorSchemeColorArray' protoField='colorSchemeColorArray'/> |
53 | <connect nodeField='beamWidth' protoField='beamWidth'/> |
54 | <connect nodeField='transparency' protoField='surfaceTransparency'/> |
55 | <connect nodeField='traceEnabled' protoField='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='MainView' position='0 -50 200'/> |
67 | <ProtoInstance name='BathymetryGenerator'> |
68 | <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'/> |
69 | <fieldValue name='surfaceTransparency' value='0.25'/> |
70 | <fieldValue name='traceEnabled' value='true'/> |
71 | </ProtoInstance> |
72 | </Scene> |
73 | </X3D> |
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 |
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. |
<!--
Color-coding legend: X3D terminology
<X3dNode
DEF='idName' field='value'/>
matches XML terminology
<XmlElement
DEF='idName' attribute='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>
-->
<!--
For additional help information about X3D scenes, please see X3D Tooltips, X3D Resources, and X3D Scene Authoring Hints.
-->