internet.com

Library

Webview II:
Network Mapping with VRML

by Kent Cearley

In the Spring 1996 issue of Web Developer®, we demonstrated graphical network monitoring using Perl and some utility libraries. In keeping with this issue's VRML focus, this time we're popping the nodes right off the screen, adding the ability to navigate through networks in three dimensions with a VRML browser.

As you may remember, our last project generated a "real-time" graphical map displaying the status of network nodes. The map was actually a simple GIF image, with node icons filled with green if they were reachable, and red if they were not. Adding a 3D representation to this mapping function goes far beyond just a useful exercise in writing VRML, though, because VRML actually lays a foundation for much more sophisticated network management.

What is VRML?

VRML, sometimes pronounced "vermil," stands for Virtual Reality Modeling Language. Like HTML, it is written in plain text, provides descriptions rather than representations, and can be built by hand with an ASCII editor.

To demonstrate how easy it is to write VRML, let's construct a single object. This is the equivalent of the conventional "Hello World" program that fledgling programmers write in other computer languages. VRML files start with the header #VRML V1.0 ascii as a standalone line.

Pay close attention to entering your uppercase and lowercase letters; unlike HTML, VRML is case-sensitive. To create an object, you can choose from among a variety of predefined shapes in VRML, including cubes, spheres, and cylinders. Placing a 3D sphere in the middle of your viewport takes only a few lines of code:

#VRML V1.0 ascii
Sphere { 
		radius 5
		}

After you key in and save this text in a file called simple.wrl, you should try opening it in a VRML-enabled browser. If you haven't already done so, you'll need to configure a browser with a VRML player or plug-in. If you've entered the text exactly as shown above, you should now see a sphere similar to the one in Figure 1.

There are several default values that help display your simple scene. A default camera perspective and light source are defined and applied by the VRML browser. Default properties for the surface of the sphere, such as color and texture, are used too. For our project, we'll stick with the default camera and light source, but we do want to control the color and texture of the objects. Here, we'll control those features with a VRML construct called the Separator. Separators enclose shapes and define properties like color, scale, and textures that apply to the object. Here's an example of how to use a Separator to change the color of our sphere to solid red:

#VRML V1.0 ascii
Separator {
	       Material {
		              diffuseColor 1 0 0 
		             }
        Sphere { 
			         radius 5
			         }
	}

The Material block can take a number of parameters that tweak the texture of the object. The diffuseColor is the color reflected off the object when a light source shines on it. The values 1 0 0 after the diffuseColor statement correspond to RGB values; that is, 100 percent red, 0 percent green, and 0 percent blue. You can specify any percentage for the RGB values using decimals.

Once you've absorbed these basics, you'll be well equipped to tackle the creation of a 3D version of the network map from the last issue.

Translating Flatland

The network GIF created in the first incarnation of this project (see Web Developer®, Spring 1996), and shown in Figure 2, was 542 x 449 pixels. Tools such as the GD library placed the figure's point of origin (0,0) in the upper left corner, with the X-axis and Y-axis extending across (x) and down (y), respectively, in positive directions.

In VRML, however, the point of origin is at the center of the scene. Positive values for the X-axis increment to the right of the screen, with negative values extending to the left. Positive values for the Y-axis increment upward toward the top of the screen, with negative values going from the center down. A new axis, the Z-axis, maps straight out of the screen toward your head (virtually) with positive values, and recedes into the screen with negative values. Thus, the point of origin in VRML is shown by the coordinates (0,0,0).

The easiest way to map the GIF coordinates to VRML is to line up the top left corner of the GIF with the center of the VRML coordinates. Our X-axis will look the same, from 0 to 542, but the Y-axis will now range from 0 to -449. For this project, we'll plot all of our objects in the lower right quandrant of the VRML scene. It really doesn't matter where you choose to map your GIF to the VRML point of origin, because we can adjust the viewer's perspective to anywhere in the scene. The technique we'll use here will simply make it easier to map items from the GIF to objects in VRML space.

For example, the center of the node called Romeo in the network GIF file is at coordinates (121,191). The size of the node measures about 32 x 32 pixels. We can create a cube in a VRML scene to represent this node as follows:

# Romeo
Separator {
		    Transform { translation 121 -191 0}
		    Material {
			           diffuseColor 0 1 0
			           }
		    Cube {
			       width	32
			       height	32
			       depth	32
			       }
		}

The # character precedes a comment in VRML. The Separator block lets us assign certain properties and operations to the shape. The Transform operation, for example, moves the shape from the default location of (0,0,0) to the coordinates (121,-191,0). We'll keep the Z-axis constant (the one representing depth) so we can arrange the nodes in the same initial layout as the GIF. You should note that the value you add for the Transform statement represents the center of the object, not its upper left corner. In this case the center of the cube is located at (121,-191,0). Because the cube measures 32 units on a side, it extends 16 units in each direction from the center. Finally, the Material property sets the color to a solid green, since 0 1 0 represents 0 percent red, 100 percent green, and 0 percent blue.

For the nodes "under" this one, we can make sure they're aligned by using the same X-axis coordinate of 121, and then define (along the Y-axis) the amount of space we want between nodes. Since our node object measures 16 units from the center to the edge, we would have to add 32 units to the Y-axis in order to put two nodes side by side. Let's add some breathing room between the two nodes to provide an additional 8 units of separation. Since our second node extends farther in the negative direction along the Y-axis, we add -40 to the first node's y coordinate (-191) to get -231. The VRML code for our next node, Juliet, is then:

# Juliet
Separator {
		    Transform { translation 121 -231 0}
		    Material {
			           diffuseColor 0 1 0
			           }
		    Cube {
			       width	32
			       height	32
			       depth	32
			       }
		}

The only value changed here is the y coordinate, as described above.

The bottom row of nodes starts with Wizard at (194,-355). We can plot the rest of the nodes in a similar fashion. This time, the y coordinate remains constant, while the x coordinate for each node increments by 40. In this way, you can quickly code all the nodes in VRML within a few minutes.

To create the line segments connecting the nodes, you can use the cylinder shape predefined in VRML. Here's an example of a vertical crossbeam used to connect Romeo, Juliet, and Hamlet:

#
# Crossbar for the voice processing nodes. 
#
Separator {
		    Transform { translation 169 -231 0 }
	       Material {
		             diffuseColor 1 1 1
		             }
	       Cylinder {
		              parts ALL
		              radius 2
		              height 82
		              }
	}

The crossbeam is spaced 48 units from the center of the three cubes on the X-axis (16 to get from the middle to the edge of the node object, plus 32 more as space). This positions the cylinder to the right of the nodes, corresponding to the line segment in the GIF diagram. Cylinders extend from a midpoint in two directions, with their width measured in "radius" units. So now we need to determine both the crossbeam's height and where it will be placed on the Y-axis. We can calculate the height by the distance between the y coordinate of the top node (Romeo: -191) and the y coordinate of the bottom one (Hamlet: -271), which is 80. The crossbeam has to be a little longer, though, so we can draw another connecting cylinder from it to the individual nodes. We adjust by adding 2, for a final height of 82.

Since the cylinder will stretch evenly in two directions to its total height--that is, 40 units in each direction, plus 2 for padding--its center has to start at one-half of its length from the topmost y coordinate (Romeo: -191). That is 40 + 191 = 231. This y coordinate ensures that the cylinder reaches up to Romeo and down to Hamlet for its full height.

You can use the same procedure to place crossbeams for each segment of nodes, once you adjust for their different orientations along the X and Y axes.

Here are a few pointers about extrapolating these techniques to other nodes:

  • The router node, depicted by a diamond on the original GIF, can be produced by rotating a cube with the Translate statement. Rotation is measured by radians, so to rotate an object 45 degrees, you'll need to specify 0.7854; to rotate 90 degrees, use 1.5708.

  • Connecting the final crossbeams together is much easier if the center of the nodes on the left align along the same x coordinate as those on the right. The same will hold true for the Y-axis with the top and bottom clusters.

    Check out--or fly through--the final version of the source code to see how these fit in. Figure 3 shows the bare-bones network as newly mapped to VRML.

    The Script

    Now that we've completed the scene description, we need to build the script that will update VRML nodes based on the fping module. Just as with the two-dimensional mapping project in the previous issue, the strategy is to go through a loop and ping each node in a nodes.dat table. This time, however, instead of updating pixel coordinates with a flood-fill, we'll be modifying the Material statement of the .wrl file passed back to the browser. To do that, we'll need some slight modifications to the CGI script as developed in the last issue.

    The first modification will be to take out the (x,y) coordinates and replace them with a status flag:

    # Collect IP nodes to ping
    open(NODES,'nodes.dat');
    while() {
    		chop;	
    		($ipaddr) = split(" ");	# take first field	
    		push(@check,$ipaddr);	# add each to list
    		$status{$ipaddr} = "G";	# flag in a status array
    		}
    close(NODES);
    

    Note that the format of the nodes.dat table has changed from last issue's project. All that's required is one IP address per line, with optional node names and comments. The IP addresses are loaded into a Perl list and also into a status array. The code $status{$ipaddr} = "G"; flags each address in the status array as green (G). Next, we send the IP address to the fping utility:

    # Send nodes to fping
    #	and check unavailable in array
    #
    open(RESULTS, "/usr/local/bin/fping -u @check 2>/dev/null |");
    while() {
    		chop;
    		$status{$_} = "R"; 
    		}
    close(RESULTS);
    

    Fping only returns IP addresses it cannot reach. Those returned are located in the table and flagged as red (R).

    For each node in our VRML file, we need to replace the Material map with the following:

    # Node Romeo
    Separator {
    		       Transform { translation 121 -191 0}
    		       Material {
    			       DiffuseColor 1 1 1 # 129.131.131.21 Romeo
    			       }
    		       Cube {
    			          width	32
    			          height	32
    			          depth	32
    			          }
    		}
    

    The IP address can appear anywhere on the color line, and any additional comments that fit on the same line can be added. This entire line will be replaced with diffuseColor 0 1 0 if the node is OK, or diffuseColor 1 0 0 if it didn't respond to a ping. These lines in the Material block should be the only lines with IP addresses in the VRML file, because the Perl script will be looking for a specific template that matches the nnn.nnn.nnn.nnn of an IP address. The following code provides this function:

    #
    # Send the WRL file to the browser 
    # 	 with status of nodes 
    # substitute all IP addresses found in table with
    #	material color indicating reachability
    #
    $| = 1;		# unbuffer output stream
    print "Content-type: x-world/x-vrml\n\n";
    open(NET,'network.wrl');	
    while() {
    		if (/\d+\.\d+i\.\d+i\.\d+/) {
                  if ($status{$&} eq "R"){ # if can't ping
    				     print "\t\tDiffuseColor 1 0 0\n";
    		                }
    			        else {                   # if reachable
    				     print "\t\tDiffuseColor 0 1 0\n";
    				     }
    }
    		else {	# no IP address, just print it as is
             print;
    		     }
    		}
    close(NET);
    

    If we call this script netvrml.cgi, we can use the following HTML to "inline" the VRML returned:

    <HTML>
    <HEAD>
    <TITLE>Network VRML Monitor</TITLE>
    </HEAD>
    <BODY>
    <H1>Network VRML Monitor</H1>
    <P>This is the prototype of network monitoring in 3D.
    <EMBED SRC="netvrml.cgi" WIDTH=600 HEIGHT=500 BORDER=0>
    </BODY>
    </HTML>

    Enhancements

    Since so many VRML browsers rely heavily on proprietary VRML enhancements or extensions, I recommend you tailor your applications for a specific presentation. This runs counter to the tenet of good Web design about writing HTML to conform to standards in order to serve the broadest user base. However, this application is designed to be a specific utility for what is presumably a small set of users within your organization. It should be easy to standardize on what browser or plug-in will be used to monitor the network. Unless you plan to put your network internals on display--which I H3ly advise against--you can afford to tailor your approach for your own requirements.

    Live3D, which is essentially WebFx rolled into Netscape, provides some useful extensions for this project. The first is a background command that tiles a graphic across the background, much like the tag in HTML. Its syntax is:

    DEF BackgroundImage Info {
          	string "spacback.gif"   # URL of the image
          	}
    

    You can also add a text tag that labels each network node, using the following code:

    
    # Romeo Label
    Separator {
    	          Transform { translation 105 -191 32 }
    	          AxisAlignment {
        		          fields [SFBitMask alignment]
        		          alignment ALIGNAXISXYZ
      	       }
    	          FontStyle {
    		                  size 10
    		                  family SANS
    		                  style BOLD
    		                  }
    	          Material {
    		                 shininess 1
    		                 specularColor 1 1 1	
    		                 }
    	          AsciiText {
    		                 string "Romeo"
    		                 justification RIGHT
    		                 }
    	   }
    

    One Live3D enhancement is the AxisAlignment statement, which keeps the text oriented toward viewers as they fly through and around the scene. The shininess and specularColor attributes make the text a bright, almost metallic white.

    AsciiText is a built-in type in VRML. It is affected by the same transformations and material mapping as the cube and other objects. In addition, it has fields for specifying font sizes and styles.

    Frames are another useful construct for enhancing the design. Three frames could be provided: one on the top left to define the application and to allow for manual polling of the network; one on the right to display the network VRML scene; and one on the bottom left that displays information about any node that is clicked in the VRML scene. This last technique can be accomplished by using a VRML construct called WWWAnchor.

    VRML allows you to define nodes that can call a URL when clicked. Live3D extends this, allowing you to target another frame to display the URL. The following code demonstrates this:

    # Romeo
    Separator {
              Transform { translation 121 -191 0}
              Material {
    			        diffuseColor 0 1 0 # 129.131.131.21 Romeo
    			        }
    	         WWWAnchor {
      	                 name "romeo.html"
    	                    target "nodeinfo"
                Cube {
    			                    width    32
    			                    height   32
    			                    depth    32
    		                 }
    	         }
    	}
    

    Note that the Cube shape must be included with the WWWAnchor field. When the cube is clicked, the target frame nodeinfo will load the romeo.html URL.

    You can also add a date/time stamp to the display, using constructs we've already covered, by appending the following to the end of the netvrml.cgi script:

    $now = &ctime(time);
    
    print <<ENDWRL;
    	Separator {
    		        Transform { translation 350 -87 0 } 		
    		        FontStyle {
    			                size 10
    			                family SANS
    			                style BOLD
    			                }
    		        AxisAlignment {
        			   fields [SFBitMask alignment]
        			   alignment ALIGNAXISXYZ
    	  		                    }
    		        Material {
    			               shininess 1
    			               specularColor 1 1 1	
    			               }
    		        AsciiText { string \"$now\" }
    		        }
    ENDWRL
    

    These enhancements are reflected in the final code, and their effects are shown in Figure 4.

    Extending

    We've just scratched the surface of what VRML can bring to a project such as this network mapping function. With the release of VRML 2.0, which will incorporate behaviors, objects could run their own Java scripts in response to events. VRML objects could communicate with other objects in the same scene, and these objects could take their own initiative in trying to resolve certain classes of problems.

    With just the VRML functions shown here, the project could be extended so that entering a node would show you processes or statistics on the inner face of the cube. Using the animated texture extensions of Live3D, you could indicate how busy a node is, in addition to its availability. And finally, this might be the justification you need for a head-mounted Virtual Reality display. You'll be able to snap on your goggles and fly through your network, checking for problems and potential bottlenecks. Who says networking can't be fun?


    Kent Cearley works in Networks and Distributed Systems at the University of Colorado, Boulder, and is the author of the book Interactive HTML3, to be published this spring by Macmillan. He can be found on the Internet at http://www.grasshopper.com/ or reached via e-mail at cearley@grasshopper.com.
    Reprinted from Web Developer® magazine, Vol. 2 No.2 May/June 1996 (c) 1996 internet.com Corporation. All rights reserved.
    Web Developer® Site Feedback
    Web Developer®
    Copyright © 2000 internet.com Corporation. All rights reserved.

http://www.internet.com/