<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN" "http://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 =' http://www.web3d.org/specifications/x3d-3.0.xsd '>
<head>
<meta name='titlecontent='SimpleBuildingConstructionPrototypes.x3d'/>
<meta name='creatorcontent='Don Brutzman'/>
<meta name='createdcontent='17 October 2001'/>
<meta name='modifiedcontent='20 October 2019'/>
<meta name='descriptioncontent='Prototypes for simple building construction: Floor, Wall, Level and Building.'/>
<meta name='identifiercontent=' https://savage.nps.edu/Savage/Buildings/UHRB/SimpleBuildingConstructionPrototypes.x3d '/>
<meta name='generatorcontent='X3D-Edit 3.2, https://savage.nps.edu/X3D-Edit'/>
<meta name='licensecontent=' ../../license.html'/>
</head>
<!-- -->
<Scene>
<WorldInfo title='SimpleBuildingConstructionPrototypes.x3d'/>
<ProtoDeclare name='Floorappinfo='Each Floor cantains the current floor surface plus a ceiling surface for the floor immediately underneath. A Floor does not include exterior or interior wall polygons.'>
<ProtoInterface>
<field name='nametype='SFStringaccessType='initializeOnly'
 appinfo='Identifying name for this Floor.'/>

<field name='descriptiontype='MFStringaccessType='initializeOnly'
 appinfo='Description info for this construction.'/>

<field name='sizetype='SFNodeaccessType='initializeOnly'
 appinfo='single-value Coordinate node with dimension x=width y=height z=depth in meters'>
<Coordinate/>
</field>
<field name='floorAppearancetype='SFNodeaccessType='initializeOnly'
 appinfo='Appearance node with Material colors ImageTexture etc. for this construction.'>
<Appearance DEF='DefaultFloorAppearance'>
<Material diffuseColor='0.2 0.2 0.2'/>
</Appearance>
</field>
<field name='ceilingAppearancetype='SFNodeaccessType='initializeOnly'
 appinfo='Appearance node with Material colors ImageTexture etc. for this construction.'>
<Appearance DEF='DefaultCeilingAppearance'>
<Material/>
</Appearance>
</field>
<field name='showSidestype='SFBoolvalue='falseaccessType='initializeOnly'
 appinfo='Whether sides are visible.'/>

<field name='widthtype='SFFloataccessType='outputOnly'
 appinfo='width of front side of floor aligned with local X axis.'/>

<field name='heighttype='SFFloataccessType='outputOnly'
 appinfo='height of vertical distance between floor and ceiling directly underneath aligned with local Y axis.'/>

<field name='depthtype='SFFloataccessType='outputOnly'
 appinfo='depth of horizontal side of floor aligned with local -Z axis.'/>

<field name='builttype='SFBoolaccessType='outputOnly'
 appinfo='Indicate whether initialization complete.'/>
</ProtoInterface>
<ProtoBody>
<Group DEF='FloorRootbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Transform DEF='LowerLeftOutsideCornerLocationbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Shape DEF='FloorbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<IS>
<connect nodeField='appearanceprotoField='floorAppearance'/>
</IS>
<IndexedFaceSet coordIndex='0 1 2 3 0 -1'>
<!-- ROUTE information for FloorCoordinate node:  [from FloorConstructionScript.floorPoints to point ] -->
<Coordinate DEF='FloorCoordinate'/>
</IndexedFaceSet>
</Shape>
<Shape DEF='CeilingbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<IS>
<connect nodeField='appearanceprotoField='ceilingAppearance'/>
</IS>
<IndexedFaceSet coordIndex='4 7 6 5 4 -1'>
<Coordinate USE='FloorCoordinate'/>
</IndexedFaceSet>
</Shape>
<!-- ROUTE information for FloorSidesSwitch node:  [from FloorConstructionScript.wallsVisible to whichChoice ] -->
<Switch DEF='FloorSidesSwitchwhichChoice='-1bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Shape DEF='FloorSidesbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<IS>
<connect nodeField='appearanceprotoField='floorAppearance'/>
</IS>
<IndexedFaceSet solid='falsecoordIndex='0 3 7 4 -1 3 2 6 7 -1 1 5 6 2 -1 0 4 5 1 -1'>
<Coordinate USE='FloorCoordinate'/>
</IndexedFaceSet>
</Shape>
</Switch>
</Transform>
<!-- ROUTE information for FloorConstructionScript node:  [from floorPoints to FloorCoordinate.point ] [from wallsVisible to FloorSidesSwitch.whichChoice ] -->
<Script DEF='FloorConstructionScriptdirectOutput='true'>
<field name='nametype='SFStringaccessType='initializeOnly'/>
<field name='descriptiontype='MFStringaccessType='initializeOnly'/>
<field name='sizetype='SFNodeaccessType='initializeOnly'/>
<field name='showSidestype='SFBoolaccessType='initializeOnly'/>
<field name='wallsVisibletype='SFInt32accessType='outputOnly'/>
<field name='floorPointstype='MFVec3faccessType='outputOnly'/>
<field name='widthtype='SFFloataccessType='outputOnly'/>
<field name='heighttype='SFFloataccessType='outputOnly'/>
<field name='depthtype='SFFloataccessType='outputOnly'/>
<field name='traceEnabledtype='SFBoolvalue='trueaccessType='initializeOnly'/>
<field name='builttype='SFBoolaccessType='outputOnly'/>
<IS>
<connect nodeField='nameprotoField='name'/>
<connect nodeField='descriptionprotoField='description'/>
<connect nodeField='sizeprotoField='size'/>
<connect nodeField='showSidesprotoField='showSides'/>
<connect nodeField='widthprotoField='width'/>
<connect nodeField='heightprotoField='height'/>
<connect nodeField='depthprotoField='depth'/>
<connect nodeField='builtprotoField='built'/>
</IS>
<![CDATA[
            
ecmascript:

function tracePrint (outputString)
{
	if (traceEnabled) Browser.print ('[Floor' + name + ']' + outputString);
}
function alwaysPrint (outputString)
{
	Browser.print ('[Floor' + name + ']' + outputString);
}
function initialize ()
{
	built = false;
	tracePrint ('description=' + description);
	tracePrint ('showSides=' + showSides);
	if (showSides == true) wallsVisible = 0; // goes to Switch whichChoice
	tracePrint ('wallsVisible=' + wallsVisible);
	if ((size.point.length == 0) || (size.point.length > 1))
		alwaysPrint ('** warning, size.point.length =' + size.point.length + ' rather than 1');
	width  = size.point[0].x;
	height = size.point[0].y;
	depth  = size.point[0].z;
	tracePrint ('(width, height, depth)=(' + width + ',' + height + ',' +  depth + ')');
	// floor is immediately above ceiling
	floorPoints = new MFVec3f (
		new SFVec3f (0, 0, 0),
		new SFVec3f (width, 0, 0),
		new SFVec3f (width, 0, -depth),
		new SFVec3f (0, 0, -depth),
		new SFVec3f (0, -height, 0),
		new SFVec3f (width, -height, 0),
		new SFVec3f (width, -height, -depth),
		new SFVec3f (0, -height, -depth));
	tracePrint ('floorPoints=' + floorPoints);
	built = true;
	tracePrint ('built=' + built);
}

          
]]>
</Script>
<ROUTE fromNode='FloorConstructionScriptfromField='floorPointstoNode='FloorCoordinatetoField='point'/>
<ROUTE fromNode='FloorConstructionScriptfromField='wallsVisibletoNode='FloorSidesSwitchtoField='whichChoice'/>
</Group>
</ProtoBody>
</ProtoDeclare>
<ProtoDeclare name='Wallappinfo='Each Wall contains exterior and interior walls.'>
<ProtoInterface>
<field name='nametype='SFStringaccessType='initializeOnly'
 appinfo='Identifying name for this Wall.'/>

<field name='descriptiontype='MFStringaccessType='initializeOnly'
 appinfo='Description info for this construction.'/>

<field name='sizetype='SFNodeaccessType='initializeOnly'
 appinfo='single-value Coordinate node with dimension x=width y=height z=depth in meters'>
<Coordinate point='0 0 0'/>
</field>
<field name='interiorAppearancetype='SFNodeaccessType='initializeOnly'
 appinfo='Appearance node with Material colors ImageTexture etc. for this construction.'>
<Appearance DEF='DefaultInteriorAppearance'>
<Material diffuseColor='0.4 0.4 0.4'/>
</Appearance>
</field>
<field name='exteriorAppearancetype='SFNodeaccessType='initializeOnly'
 appinfo='Appearance node with Material colors ImageTexture etc. for this construction.'>
<Appearance DEF='DefaultExteriorAppearance'>
<Material diffuseColor='0.6 0.6 0.6'/>
</Appearance>
</field>
<field name='showSidestype='SFBoolvalue='falseaccessType='initializeOnly'
 appinfo='Whether sides are visible.'/>

<field name='widthtype='SFFloataccessType='outputOnly'
 appinfo='width of horizontal side of wall aligned with local X axis.'/>

<field name='heighttype='SFFloataccessType='outputOnly'
 appinfo='height of Wall aligned with local Y axis.'/>

<field name='depthtype='SFFloataccessType='outputOnly'
 appinfo='depth of horizontal thickness of Wall aligned with local -Z axis.'/>

<field name='builttype='SFBoolaccessType='outputOnly'
 appinfo='Indicate whether initialization complete.'/>
</ProtoInterface>
<ProtoBody>
<Group DEF='WallRootbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Transform DEF='LowerLeftOutsideCornerLocationWallbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Shape DEF='InteriorWallbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<IS>
<connect nodeField='appearanceprotoField='interiorAppearance'/>
</IS>
<!-- only draw interior-facing side for efficiency, and also so that view piercing external wall immediately sees interior -->
<IndexedFaceSet coordIndex='4 7 6 5 4 -1'>
<!-- ROUTE information for WallCoordinate node:  [from WallConstructionScript.coordinatePoints to point ] -->
<Coordinate DEF='WallCoordinate'/>
</IndexedFaceSet>
</Shape>
<Shape DEF='ExteriorWallbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<IS>
<connect nodeField='appearanceprotoField='exteriorAppearance'/>
</IS>
<IndexedFaceSet coordIndex='0 1 2 3 0 -1'>
<Coordinate USE='WallCoordinate'/>
</IndexedFaceSet>
</Shape>
<!-- ROUTE information for WallSidesSwitch node:  [from WallConstructionScript.wallsVisible to whichChoice ] -->
<Switch DEF='WallSidesSwitchwhichChoice='-1bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Shape DEF='WallSidesbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<IS>
<connect nodeField='appearanceprotoField='exteriorAppearance'/>
</IS>
<IndexedFaceSet coordIndex='0 3 7 4 -1 3 2 6 7 -1 1 5 6 2 -1 0 4 5 1 -1'>
<Coordinate USE='WallCoordinate'/>
</IndexedFaceSet>
</Shape>
</Switch>
</Transform>
<!-- ROUTE information for WallConstructionScript node:  [from coordinatePoints to WallCoordinate.point ] [from wallsVisible to WallSidesSwitch.whichChoice ] -->
<Script DEF='WallConstructionScriptdirectOutput='true'>
<field name='nametype='SFStringaccessType='initializeOnly'/>
<field name='descriptiontype='MFStringaccessType='initializeOnly'/>
<field name='sizetype='SFNodeaccessType='initializeOnly'/>
<field name='showSidestype='SFBoolaccessType='initializeOnly'/>
<field name='wallsVisibletype='SFInt32accessType='outputOnly'/>
<field name='coordinatePointstype='MFVec3faccessType='outputOnly'/>
<field name='widthtype='SFFloataccessType='outputOnly'/>
<field name='heighttype='SFFloataccessType='outputOnly'/>
<field name='depthtype='SFFloataccessType='outputOnly'/>
<field name='traceEnabledtype='SFBoolvalue='trueaccessType='initializeOnly'/>
<field name='builttype='SFBoolaccessType='outputOnly'/>
<IS>
<connect nodeField='nameprotoField='name'/>
<connect nodeField='descriptionprotoField='description'/>
<connect nodeField='sizeprotoField='size'/>
<connect nodeField='showSidesprotoField='showSides'/>
<connect nodeField='widthprotoField='width'/>
<connect nodeField='heightprotoField='height'/>
<connect nodeField='depthprotoField='depth'/>
<connect nodeField='builtprotoField='built'/>
</IS>
<![CDATA[
            
ecmascript:

function tracePrint (outputString)
{
	if (traceEnabled) Browser.print ('[Wall' + name + ']' + outputString);
}
function alwaysPrint (outputString)
{
	Browser.print ('[Wall' + name + ']' + outputString);
}
function initialize ()
{
	built = false;
	tracePrint ('description=' + description);
	tracePrint ('showSides=' + showSides);
	if (showSides == true) wallsVisible = 0; // goes to Switch whichChoice
	tracePrint ('wallsVisible=' + wallsVisible);
	if ((size.point.length == 0) || (size.point.length > 1))
		alwaysPrint ('** warning, size.point.length =' + size.point.length + ' rather than 1');
	width  = size.point[0].x;
	height = size.point[0].y;
	depth  = size.point[0].z;
	tracePrint ('(width, height, depth)=(' + width + ',' + height + ',' +  depth + ')');
	coordinatePoints = new MFVec3f (
		new SFVec3f (0, 0, 0),
		new SFVec3f (width, 0, 0),
		new SFVec3f (width, height, 0),
		new SFVec3f (0, height, 0),
		new SFVec3f (0, 0, -depth),
		new SFVec3f (width, 0, -depth),
		new SFVec3f (width, height, -depth),
		new SFVec3f (0, height, -depth));
	tracePrint ('coordinatePoints=' + coordinatePoints);
	built = true;
	tracePrint ('built=' + built);
}

          
]]>
</Script>
<ROUTE fromNode='WallConstructionScriptfromField='coordinatePointstoNode='WallCoordinatetoField='point'/>
<ROUTE fromNode='WallConstructionScriptfromField='wallsVisibletoNode='WallSidesSwitchtoField='whichChoice'/>
</Group>
</ProtoBody>
</ProtoDeclare>
<ProtoDeclare name='Levelappinfo='collection of a Floor and four Walls working in order up from lowest level (i.e. story) of the Building'>
<ProtoInterface>
<field name='nametype='SFStringaccessType='initializeOnly'
 appinfo='Identifying name for this Level.'/>

<field name='descriptiontype='MFStringaccessType='initializeOnly'
 appinfo='Description info for this construction.'/>

<field name='floortype='MFNodeaccessType='initializeOnly'
 appinfo='contains single Floor node'>
<Group bboxCenter='0 0 0bboxSize='-1 -1 -1'/>
</field>
<field name='frontWalltype='MFNodeaccessType='initializeOnly'
 appinfo='contains single front Wall node'>
<ProtoInstance name='Wall'/>
</field>
<field name='rightWalltype='MFNodeaccessType='initializeOnly'
 appinfo='contains single right-side Wall node'>
<ProtoInstance name='Wall'/>
</field>
<field name='rearWalltype='MFNodeaccessType='initializeOnly'
 appinfo='contains single rear Wall node'>
<ProtoInstance name='Wall'/>
</field>
<field name='leftWalltype='MFNodeaccessType='initializeOnly'
 appinfo='contains single left-side Wall node'>
<ProtoInstance name='Wall'/>
</field>
<field name='widthtype='SFFloataccessType='outputOnly'
 appinfo='Calculated width of horizontal side of Level aligned with local X axis.'/>

<field name='heighttype='SFFloataccessType='outputOnly'
 appinfo='Calculated height of Level aligned with local Y axis.'/>

<field name='depthtype='SFFloataccessType='outputOnly'
 appinfo='Calculated depth of horizontal thickness of Level aligned with local -Z axis.'/>

<field name='builttype='SFBoolaccessType='outputOnly'
 appinfo='Indicate whether initialization complete.'/>
</ProtoInterface>
<ProtoBody>
<Group DEF='LevelRootbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Transform DEF='FloorTransformbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<IS>
<connect nodeField='childrenprotoField='floor'/>
</IS>
</Transform>
<Transform DEF='FrontWallTransformbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<IS>
<connect nodeField='childrenprotoField='frontWall'/>
</IS>
</Transform>
<!-- ROUTE information for RightWallTransform node:  [from LevelConstructionScript.rightTranslation to translation ] -->
<Transform DEF='RightWallTransformrotation='0 1 0 1.57079bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<IS>
<connect nodeField='childrenprotoField='rightWall'/>
</IS>
</Transform>
<!-- ROUTE information for RearWallTransform node:  [from LevelConstructionScript.rearTranslation to translation ] -->
<Transform DEF='RearWallTransformrotation='0 1 0 3.1416bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<IS>
<connect nodeField='childrenprotoField='rearWall'/>
</IS>
</Transform>
<!-- ROUTE information for LeftWallTransform node:  [from LevelConstructionScript.leftTranslation to translation ] -->
<Transform DEF='LeftWallTransformrotation='0 1 0 4.7124bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<IS>
<connect nodeField='childrenprotoField='leftWall'/>
</IS>
</Transform>
<!-- ROUTE information for LevelConstructionScript node:  [from LevelRecalculateUntilBuilt.cycleTime to recheckUntilBuilt ] [from rightTranslation to RightWallTransform.translation ] [from rearTranslation to RearWallTransform.translation ] [from leftTranslation to LeftWallTransform.translation ] [from built to LevelBuiltFilter.set_boolean ] -->
<Script DEF='LevelConstructionScriptdirectOutput='true'>
<field name='nametype='SFStringaccessType='initializeOnly'/>
<field name='descriptiontype='MFStringaccessType='initializeOnly'/>
<field name='floortype='MFNodeaccessType='initializeOnly'/>
<field name='frontWalltype='MFNodeaccessType='initializeOnly'/>
<field name='rightWalltype='MFNodeaccessType='initializeOnly'/>
<field name='rearWalltype='MFNodeaccessType='initializeOnly'/>
<field name='leftWalltype='MFNodeaccessType='initializeOnly'/>
<field name='widthtype='SFFloataccessType='outputOnly'/>
<field name='heighttype='SFFloataccessType='outputOnly'/>
<field name='depthtype='SFFloataccessType='outputOnly'/>
<field name='rightTranslationtype='SFVec3faccessType='outputOnly'/>
<field name='rearTranslationtype='SFVec3faccessType='outputOnly'/>
<field name='leftTranslationtype='SFVec3faccessType='outputOnly'/>
<field name='traceEnabledtype='SFBoolvalue='trueaccessType='initializeOnly'/>
<field name='recheckUntilBuilttype='SFTimeaccessType='inputOnly'
 appinfo='New floor or wall initialization may be complete check and recalculate until built'/>

<field name='builttype='SFBoolaccessType='outputOnly'/>
<IS>
<connect nodeField='nameprotoField='name'/>
<connect nodeField='descriptionprotoField='description'/>
<connect nodeField='floorprotoField='floor'/>
<connect nodeField='frontWallprotoField='frontWall'/>
<connect nodeField='rightWallprotoField='rightWall'/>
<connect nodeField='rearWallprotoField='rearWall'/>
<connect nodeField='leftWallprotoField='leftWall'/>
<connect nodeField='widthprotoField='width'/>
<connect nodeField='heightprotoField='height'/>
<connect nodeField='depthprotoField='depth'/>
<connect nodeField='builtprotoField='built'/>
</IS>
<![CDATA[
            
ecmascript:

var firstLoopWhileTrueCompleted;

function tracePrint (outputString)
{
	if (traceEnabled) Browser.print ('[Level' + name + ']' + outputString);
}
function alwaysPrint (outputString)
{
	Browser.print ('[Level' + name + ']' + outputString);
}
function initialize ()
{
	built = false;
	firstLoopWhileTrueCompleted = false;
	alwaysPrint ('initialize, built=' + built);
}
function recheckUntilBuilt (value)
{
	if      (built == true)
	{
		built = true; // resend to trigger cancellation event for TimeSensor
		if (firstLoopWhileTrueCompleted)
			alwaysPrint ('recheckUntilBuilt() continuous built=true indicates internal error');
		else firstLoopWhileTrueCompleted = true;
		return;  // done
	}
	alwaysPrint ('recheckUntilBuilt testing...');
	// following are single nodes, cast as MFNode type for IS/connect matchups
	if      (floor[0].built == false)	return;  // not yet ready
	else if (frontWall[0].built == false)	return;
	else if (rightWall[0].built == false)	return;
	else if (rearWall[0].built == false)	return;
	else if (leftWall[0].built == false)	return;
	alwaysPrint ('recheckUntilBuilt ready, initializing Level...');

	alwaysPrint ('description=' + description);
	if (floor)
	{
	//	tracePrint ('floor found');
		if (floor.length > 1)
			alwaysPrint ('** warning, more than one floor found (' +
				floor.length + ' nodes total)');
		tracePrint ('floor (width, height, depth)=(' +
			floor[0].width + ',' + floor[0].height + ',' +  floor[0].depth + ')');
	}
	else	tracePrint ('floor not found');

	if (frontWall)
	{
	//	tracePrint ('frontWall found');
		if (frontWall > 1)
			alwaysPrint ('** warning, more than one frontWall found (' +
				frontWall.length + ' nodes total)');
		tracePrint ('frontWall (width, height, depth)=(' +
			frontWall[0].width + ',' + frontWall[0].height + ',' +  frontWall[0].depth + ')');
	}
	else	tracePrint ('frontWall not found');

	if (rightWall)
	{
	//	tracePrint ('rightWall found');
		if (rightWall > 1)
			alwaysPrint ('** warning, more than one rightWall found (' +
				frontWall.length + ' nodes total)');
		tracePrint ('rightWall (width, height, depth)=(' +
			rightWall[0].width + ',' + rightWall[0].height + ',' +  rightWall[0].depth + ')');
	}

	else	tracePrint ('rightWall not found');

	if (rearWall)
	{
	//	tracePrint ('rearWall found');
		if (frontWall > 1)
			alwaysPrint ('** warning, more than one rearWall found (' +
				rearWall + ' nodes total)');
		tracePrint ('rearWall (width, height, depth)=(' +
			rearWall[0].width + ',' + rearWall[0].height + ',' +  rearWall[0].depth + ')');
	}
	else	tracePrint ('rearWall not found');

	if (leftWall)
	{
	//	tracePrint ('leftWall found');
		if (frontWall > 1)
			alwaysPrint ('** warning, more than one leftWall found (' +
				leftWall.length + ' nodes total)');
		tracePrint ('leftWall (width, height, depth)=(' +
			leftWall[0].width + ',' + leftWall[0].height + ',' +  leftWall[0].depth + ')');
	}
	else	tracePrint ('leftWall not found');

	if (floor && frontWall)
	{
		if ((floor[0].width != frontWall[0].width) && (floor[0].width != 0) && (frontWall[0].width != 0))
			alwaysPrint ('** warning, floor/frontWall width mismatch');
	}
	if (floor && rearWall)
	{
		if ((floor[0].width != rearWall[0].width) && (floor[0].width != 0) && (rearWall[0].width != 0))
			alwaysPrint ('** warning, floor/rearWall width mismatch');
	}
	if (floor && rightWall)
	{
		if ((floor[0].depth != rightWall[0].width) && (floor[0].depth != 0) && (rightWall[0].width != 0))
			alwaysPrint ('** warning, floor.depth/rightWall.width mismatch');
	}
	if (floor && leftWall)
	{
		if ((floor[0].depth != leftWall[0].width) && (floor[0].depth != 0) && (leftWall[0].width != 0))
			alwaysPrint ('** warning, floor.depth/leftWall.width mismatch');
	}
	if (frontWall && rearWall)
	{
		if ((frontWall[0].width != rearWall[0].width) && (frontWall[0].width != 0) && (rearWall[0].width != 0))
			alwaysPrint ('** warning, frontWall/rearWall width mismatch');
	}
	if (leftWall && rightWall)
	{
		if ((leftWall[0].width != rightWall[0].width) && (leftWall[0].width != 0) && (rightWall[0].width != 0))
			alwaysPrint ('** warning, leftWall/rightWall width mismatch');
	}

	// find first nonzero values
	width = 0;
	if (floor)                     width = floor[0].width;
	if (frontWall && (width == 0)) width = frontWall[0].width;
	if (rearWall  && (width == 0)) width = rearWall[0].width;

	height = 0;
	if      (frontWall)                  height = frontWall[0].height;
	if      (rightWall && (height == 0)) height = rightWall[0].height;
	else if (rearWall  && (height == 0)) height = rearWall[0].height;
	else if (leftWall  && (height == 0)) height = leftWall[0].height;

	depth = 0;
	if (floor)                     depth = floor[0].depth;
	if (rightWall && (depth == 0)) depth = rightWall[0].depth;
	if (leftWall  && (depth == 0)) depth = leftWall[0].depth;

	tracePrint ('(width, height, depth)=(' + width + ',' + height + ',' +  depth + ')');

	// translate wall centers (not corners)
	rightTranslation = new SFVec3f (width, 0, 0);
	tracePrint ('rightTranslation=' + rightTranslation);
	rearTranslation = new SFVec3f  (width, 0, -depth);
	tracePrint ('rearTranslation=' + rearTranslation);
	leftTranslation = new SFVec3f  (0, 0, -width/2);
	tracePrint ('leftTranslation=' + leftTranslation);
	built = true;
	tracePrint ('built=' + built);
}

          
]]>
</Script>
<ROUTE fromNode='LevelConstructionScriptfromField='rightTranslationtoNode='RightWallTransformtoField='translation'/>
<ROUTE fromNode='LevelConstructionScriptfromField='rearTranslationtoNode='RearWallTransformtoField='translation'/>
<ROUTE fromNode='LevelConstructionScriptfromField='leftTranslationtoNode='LeftWallTransformtoField='translation'/>
<Group DEF='LevelInitializeAfterChildrenReadybboxCenter='0 0 0bboxSize='-1 -1 -1'>
<!-- ROUTE information for LevelBuiltFilter node:  [from LevelConstructionScript.built to set_boolean ] [from inputTrue to LevelBuiltNegation.set_boolean ] -->
<BooleanFilter DEF='LevelBuiltFiltercontainerField='children'/>
<!-- ROUTE information for LevelBuiltNegation node:  [from LevelBuiltFilter.inputTrue to set_boolean ] [from inputNegate to LevelRecalculateUntilBuilt.enabled ] -->
<BooleanFilter DEF='LevelBuiltNegationcontainerField='children'/>
<!-- ROUTE information for LevelRecalculateUntilBuilt node:  [from LevelBuiltNegation.inputNegate to enabled ] [from cycleTime to LevelConstructionScript.recheckUntilBuilt ] -->
<TimeSensor DEF='LevelRecalculateUntilBuiltcycleInterval='0.1loop='true'/>
<ROUTE fromNode='LevelConstructionScriptfromField='builttoNode='LevelBuiltFiltertoField='set_boolean'/>
<ROUTE fromNode='LevelBuiltFilterfromField='inputTruetoNode='LevelBuiltNegationtoField='set_boolean'/>
<ROUTE fromNode='LevelBuiltNegationfromField='inputNegatetoNode='LevelRecalculateUntilBuilttoField='enabled'/>
<ROUTE fromNode='LevelRecalculateUntilBuiltfromField='cycleTimetoNode='LevelConstructionScripttoField='recheckUntilBuilt'/>
</Group>
</Group>
</ProtoBody>
</ProtoDeclare>
<ProtoDeclare name='Buildingappinfo='Collect prototypes for levels floors and walls to create a simple Building.'>
<ProtoInterface>
<field name='nametype='SFStringaccessType='initializeOnly'
 appinfo='Identifying name of this Building.'/>

<field name='descriptiontype='MFStringaccessType='initializeOnly'
 appinfo='Description info for this construction.'/>

<field name='authorAssisttype='SFBoolvalue='trueaccessType='initializeOnly'
 appinfo='whether or not to display author assist tools such as coordinate axes measuring grids etc.'/>

<field name='xHeadingtype='SFFloatvalue='0.0accessType='initializeOnly'
 appinfo='compass direction in degrees of building X axis as seen when regarding front face of building pointing from left side to right side.'/>

<field name='orientationtype='SFRotationaccessType='outputOnly'
 appinfo='output rotation value calculated from xHeading as (0 1 0 xHeading * 2pi / 360)'/>

<field name='latitudetype='SFStringaccessType='initializeOnly'
 appinfo='example value: 120.30 E'/>

<field name='longitudetype='SFStringaccessType='initializeOnly'
 appinfo='example value: 20.45 N'/>

<field name='levelstype='MFNodeaccessType='initializeOnly'
 appinfo='contains array of Level nodes'>
<ProtoInstance name='Level'/>
</field>
<field name='rooftype='SFNodeaccessType='initializeOnly'
 appinfo='Geometry for Roof positioned above topmost Level'>
<Group bboxCenter='0 0 0bboxSize='-1 -1 -1'/>
</field>
<field name='roofHeighttype='SFFloatvalue='0accessType='initializeOnly'
 appinfo='height value for provided Roof geometry.'/>

<field name='widthtype='SFFloataccessType='outputOnly'
 appinfo='Calculated width of horizontal side of Building aligned with local X axis.'/>

<field name='heighttype='SFFloataccessType='outputOnly'
 appinfo='Calculated height of Building aligned with local Y axis.'/>

<field name='depthtype='SFFloataccessType='outputOnly'
 appinfo='Calculated depth of horizontal thickness of Building aligned with local -Z axis.'/>

<field name='builttype='SFBoolaccessType='outputOnly'
 appinfo='Indicate whether initialization complete.'/>
</ProtoInterface>
<ProtoBody>
<Group bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<!-- ROUTE information for AuthorAssist1 node:  [from BuildingConstructionScript.authorAssistChoice to whichChoice ] -->
<Switch DEF='AuthorAssist1whichChoice='-1bboxCenter='0 0 0bboxSize='-1 -1 -1'> </Switch>
<Group DEF='BuildingRootbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Transform DEF='LevelsRootbboxCenter='0 0 0bboxSize='-1 -1 -1'>
<!-- ROUTE information for AuthorAssist2 node:  [from BuildingConstructionScript.authorAssistChoice to whichChoice ] -->
<Switch DEF='AuthorAssist2whichChoice='-1bboxCenter='0 0 0bboxSize='-1 -1 -1'> </Switch>
</Transform>
<!-- ROUTE information for BuildingConstructionScript node:  [from BuildingRecalculateUntilBuilt.cycleTime to recheckUntilBuilt ] [from authorAssistChoice to AuthorAssist1.whichChoice ] [from authorAssistChoice to AuthorAssist2.whichChoice ] [from scale to CoordinateAxesTransform.scale ] [from built to BuildingBuiltFilter.set_boolean ] -->
<Script DEF='BuildingConstructionScriptdirectOutput='true'>
<field name='nametype='SFStringaccessType='initializeOnly'/>
<field name='descriptiontype='MFStringaccessType='initializeOnly'/>
<field name='xHeadingtype='SFFloataccessType='initializeOnly'/>
<field name='orientationtype='SFRotationaccessType='outputOnly'/>
<field name='latitudetype='SFStringaccessType='initializeOnly'/>
<field name='longitudetype='SFStringaccessType='initializeOnly'/>
<field name='authorAssisttype='SFBoolaccessType='initializeOnly'/>
<field name='levelstype='MFNodeaccessType='initializeOnly'/>
<field name='rooftype='SFNodeaccessType='initializeOnly'/>
<field name='roofHeighttype='SFFloataccessType='initializeOnly'/>
<field name='LevelsRoottype='SFNodeaccessType='initializeOnly'>
<Transform USE='LevelsRootbboxCenter='0 0 0bboxSize='-1 -1 -1'/>
</field>
<field name='widthtype='SFFloataccessType='outputOnly'/>
<field name='heighttype='SFFloataccessType='outputOnly'/>
<field name='depthtype='SFFloataccessType='outputOnly'/>
<field name='scaletype='SFVec3faccessType='outputOnly'/>
<field name='authorAssistChoicetype='SFInt32accessType='outputOnly'/>
<field name='traceEnabledtype='SFBoolvalue='trueaccessType='initializeOnly'/>
<field name='recheckUntilBuilttype='SFTimeaccessType='inputOnly'
 appinfo='New floor or wall initialization may be complete check and recalculate until built'/>

<field name='builttype='SFBoolaccessType='outputOnly'/>
<IS>
<connect nodeField='nameprotoField='name'/>
<connect nodeField='descriptionprotoField='description'/>
<connect nodeField='authorAssistprotoField='authorAssist'/>
<connect nodeField='xHeadingprotoField='xHeading'/>
<connect nodeField='orientationprotoField='orientation'/>
<connect nodeField='latitudeprotoField='latitude'/>
<connect nodeField='longitudeprotoField='longitude'/>
<connect nodeField='levelsprotoField='levels'/>
<connect nodeField='roofprotoField='roof'/>
<connect nodeField='roofHeightprotoField='roofHeight'/>
<connect nodeField='widthprotoField='width'/>
<connect nodeField='heightprotoField='height'/>
<connect nodeField='depthprotoField='depth'/>
<connect nodeField='builtprotoField='built'/>
</IS>
<![CDATA[
              
ecmascript:

var firstLoopWhileTrueCompleted;

function tracePrint (outputString)
{
	if (traceEnabled) Browser.print ('[Building' + name + ']' + outputString);
}
function alwaysPrint (outputString)
{
	Browser.print ('[Building' + name + ']' + outputString);
}
function initialize ()
{
	built = false;
	firstLoopWhileTrueCompleted = false;
	alwaysPrint ('initialize, built=' + built);
}
function recheckUntilBuilt (value)
{
	if      (built == true)
	{
		built = true; // resend to trigger cancellation event for TimeSensor
		if (firstLoopWhileTrueCompleted)
			alwaysPrint ('recheckUntilBuilt() continuous built=true indicates internal error');
		else firstLoopWhileTrueCompleted = true;
		return;  // done
	}
	tracePrint ('recheckUntilBuilt testing...');
	if      (built == true)			return;  // done
	for (i=0; i < levels.length; i++)
	{
		if (levels[i].built == false)	return;  // not yet ready
	}
	tracePrint ('recheckUntilBuilt ready!');

	alwaysPrint ('description=' + description);
	if (levels.length == 0)
	{
		alwaysPrint ('** warning, no levels found');
		return;
	}
	orientation = new SFRotation (0, 1, 0, -xHeading * 3.14159 / 180.0);
	LevelsRoot.rotation = orientation;
	tracePrint ('xHeading=' + xHeading + ' degrees,' + 'orientation=' + orientation);

	width  = 0;
	depth  = 0;
	incrementalHeight = 0;
	// first child of LevelsRoot is oriented AuthorAssist2 Switch
	for (i=0; i < levels.length; i++)
	{
		tracePrint ('level[' + i + ']');
		// compute max values for width, height, depth
		if (width  < levels[i].width)  width   = levels[i].width;
		if (depth  < levels[i].depth)  depth   = levels[i].depth;

		newTransform ='Transform {' +
		'translation 0' + incrementalHeight + ' 0' +
		'}';
		tracePrint ('newTransform=' + newTransform);
		newTransformNode = Browser.createVrmlFromString (newTransform); // returns MFNode
		// append newTransformNode to LevelsRoot.children
		LevelsRoot.children[i+1] = newTransformNode[0];
		// append current Level to current newTransformNode
		newTransformNode[0].children[0] = levels[i];

		incrementalHeight += levels[i].height;
		tracePrint ('incrementalHeight=' + incrementalHeight);
	}
	childCount = levels.length + 1;
	if (roof)
	{
		tracePrint ('roof');
		newTransform ='Transform {' +
		'translation 0' + incrementalHeight + ' 0' +
		'}';
		tracePrint ('newTransform=' + newTransform);
		newTransformNode = Browser.createVrmlFromString (newTransform); // returns MFNode
		// append newTransformNode to LevelsRoot.children
		LevelsRoot.children[childCount] = newTransformNode[0];
		childCount++;
		// append roof to current newTransformNode
		newTransformNode[0].children[0] = roof;
		incrementalHeight += roofHeight;
	}
	else alwaysPrint ('** warning, no roof found');

	height = incrementalHeight;
	tracePrint ('(width, height, depth)=(' + width + ',' + height + ',' +  depth + ')');
	maxDimension = width;
	if (maxDimension < height) maxDimension = height;
	if (maxDimension < depth)  maxDimension = depth;
	scale = new SFVec3f (maxDimension * 1.1, maxDimension * 1.1, maxDimension * 1.1);

	newView ='Viewpoint {' +
	'description \"' + name + ' (' + latitude + ',' + longitude + ')\"' +
	'position' + (width/2) + ' ' + (height*2.0/3.0) + ' ' + (depth*3) + ' ' +
	'}';
	tracePrint ('newView=' + newView);
	newViewNode = Browser.createVrmlFromString (newView); // returns MFNode
	// append newViewNode to LevelsRoot.children
	LevelsRoot.children[childCount] = newViewNode[0];
	childCount++;

	newView ='Viewpoint {' +
	'description \"' + name + ' (above)\"' +
	'position' + (width/2) + ' ' + (height*3.0) + ' ' + (-depth/2) + ' ' +
	'orientation 1 0 0 -1.57' +
	'}';
	tracePrint ('newView=' + newView);
	newViewNode = Browser.createVrmlFromString (newView); // returns MFNode
	// append newViewNode to LevelsRoot.children
	LevelsRoot.children[childCount] = newViewNode[0];
	childCount++;

	if (authorAssist)
	{
		tracePrint ('authorAssist');
		authorAssistChoice = 0;
	}
	else	authorAssistChoice = -1;

	tracePrint ('LevelsRoot childCount=' + childCount + ' (Switch + # levels + [roof] + Viewpoint*2)');
	built = true;
	tracePrint ('built=' + built);
}

            
]]>
</Script>
<ROUTE fromNode='BuildingConstructionScriptfromField='authorAssistChoicetoNode='AuthorAssist1toField='whichChoice'/>
<ROUTE fromNode='BuildingConstructionScriptfromField='authorAssistChoicetoNode='AuthorAssist2toField='whichChoice'/>
<ROUTE fromNode='BuildingConstructionScriptfromField='scaletoNode='CoordinateAxesTransformtoField='scale'/>
<Group DEF='BuildingInitializeAfterChildrenReadybboxCenter='0 0 0bboxSize='-1 -1 -1'>
<!-- ROUTE information for BuildingBuiltFilter node:  [from BuildingConstructionScript.built to set_boolean ] [from inputTrue to BuildingBuiltNegation.set_boolean ] -->
<BooleanFilter DEF='BuildingBuiltFiltercontainerField='children'/>
<!-- ROUTE information for BuildingBuiltNegation node:  [from BuildingBuiltFilter.inputTrue to set_boolean ] [from inputNegate to BuildingRecalculateUntilBuilt.enabled ] -->
<BooleanFilter DEF='BuildingBuiltNegationcontainerField='children'/>
<!-- ROUTE information for BuildingRecalculateUntilBuilt node:  [from BuildingBuiltNegation.inputNegate to enabled ] [from cycleTime to BuildingConstructionScript.recheckUntilBuilt ] -->
<TimeSensor DEF='BuildingRecalculateUntilBuiltcycleInterval='0.1loop='true'/>
<ROUTE fromNode='BuildingConstructionScriptfromField='builttoNode='BuildingBuiltFiltertoField='set_boolean'/>
<ROUTE fromNode='BuildingBuiltFilterfromField='inputTruetoNode='BuildingBuiltNegationtoField='set_boolean'/>
<ROUTE fromNode='BuildingBuiltNegationfromField='inputNegatetoNode='BuildingRecalculateUntilBuilttoField='enabled'/>
<ROUTE fromNode='BuildingRecalculateUntilBuiltfromField='cycleTimetoNode='BuildingConstructionScripttoField='recheckUntilBuilt'/>
</Group>
</Group>
</Group>
</ProtoBody>
</ProtoDeclare>
<!-- ============================ -->
<Viewpoint description='SimpleBuildingConstructionPrototypesposition='0 0 12'/>
<Background groundAngle='1.57groundColor='0.6 0.9 0.6 0.6 0.9 0.6skyColor='0.6 0.6 0.9'/>
<Anchor description='SimpleBuildingConstructionExampleparameter='"target=_blank"bboxCenter='0 0 0bboxSize='-1 -1 -1'
  url=' "SimpleBuildingConstructionExample.wrl" "https://savage.nps.edu/Savage/Buildings/UHRB/SimpleBuildingConstructionExample.wrl" "SimpleBuildingConstructionExample.x3d" "https://savage.nps.edu/Savage/Buildings/UHRB/SimpleBuildingConstructionExample.x3d" '>
<Shape bboxCenter='0 0 0bboxSize='-1 -1 -1'>
<Text string='"SimpleBuildingConstructionPrototypes" "is a prototype definition file" "" "Click this text to see" "SimpleBuildingConstructionExample"'>
<FontStyle justify='"MIDDLE" "MIDDLE"'/>
</Text>
<Appearance>
<Material diffuseColor='0.2 0.2 0.8'/>
</Appearance>
</Shape>
</Anchor>
</Scene>
</X3D>
<!--

Index for ProtoDeclare definitions : Building, Floor, Level, Wall

Index for DEF nodes : AuthorAssist1, AuthorAssist2, AuthorAssistTransform2, BuildingBuiltFilter, BuildingBuiltNegation, BuildingConstructionScript, BuildingInitializeAfterChildrenReady, BuildingRecalculateUntilBuilt, BuildingRoot, Ceiling, CoordinateAxes, CoordinateAxesTransform, DefaultCeilingAppearance, DefaultExteriorAppearance, DefaultFloorAppearance, DefaultInteriorAppearance, ExteriorWall, Floor, FloorConstructionScript, FloorCoordinate, FloorRoot, FloorSides, FloorSidesSwitch, FloorTransform, FrontWallTransform, InteriorWall, LeftWallTransform, LevelBuiltFilter, LevelBuiltNegation, LevelConstructionScript, LevelInitializeAfterChildrenReady, LevelRecalculateUntilBuilt, LevelRoot, LevelsRoot, LowerLeftOutsideCornerLocation, LowerLeftOutsideCornerLocationWall, RearWallTransform, RightWallTransform, WallConstructionScript, WallCoordinate, WallRoot, WallSides, WallSidesSwitch

Index for Viewpoint image : Viewpoint_1
-->

<!-- Color key: <X3dNode DEF='idName' field='value'/> matches <XmlElement DEF='idName' attribute='value'/>
(Light blue background: behavior node) (Grey background: inserted documentation) (Magenta background: X3D Extensibility)
    <Prototype name='ProtoName'> <field name='fieldName'/> </Prototype> -->

<!-- Additional help information about X3D scenes: X3D Resources, X3D Scene Authoring Hints and X3D Tooltips -->