XOBJVIEW: Under the Hood

In version 5.0, IDL introduced object graphics, a new way for rendering graphics in the language. One handy command for drawing such graphics is XOBJVIEW. For example if we have a surface object, we can draw it with XOBJVIEW:
	IDL> oSurface = obj_new('IDLgrSurface', dist(40)) ; create surface object
	IDL> xobjview, oSurface

(If you issue the above commands in IDL, you can rotate the resulting visualization by clicking and dragging on it.)

This document explores some of the inner workings of the XOBJVIEW command.

XOBJVIEW itself is written in the IDL language. Its source code is available to IDL users in the file xobjview.pro. If you've ever looked in that file, you probably noticed that XOBJVIEW relies on a class called IDLexObjviewWid, and IDLexObjviewWid relies on other IDLex classes. This family of classes, all of which have "ex" in their name, was originally started as example code; hence the "ex" nomenclature. Nowadays many of the IDLex classes are used in XOBJVIEW, XVOLUME, and XPLOT3D. With these classes, the underlying designs of XOBJVIEW, XVOLUME, and XPLOT3D follow a variation of the Bridge design pattern from the Gamma, et al. book Design Patterns. The "bridge" in this case separates the commands' GUI widgets from objects that implement the widgets' behavior. This division makes the code more flexible for re-use. For example, if you wanted to, you could probably write your own widget interface ("skin") for XOBJVIEW in Visual Basic and re-use just the graphics parts of XOBJVIEW to implement your widgets' behavior. The graphics parts of XOBJVIEW are available in that way because of the division effected by the bridge pattern. (You may need to write some simple wrapper classes to make the IDL code callable from Visual Basic, but I suspect it would not be hard to do.)

Here is a diagram giving an overview of some of the IDLex family of classes. The diagram is a Visio file (.vsd). If you don't have Visio installed on your computer, a free viewer can be downloaded from office.microsoft.com/downloads . The viewer is for Microsoft Windows only. For those of you who don't have access to a Windows machine, here is a non-Visio version of the same diagram. Classes on the left side of the diagram comprise widget GUI, and classes on the right side of the diagram comprise graphics view and behavior.

One class to take note of in the diagram is IDLexWidget. This class embodies the notion of "widget object" often discussed on the USENET newsgroup comp.lang.idl-pvwave. To wit, classes derived from IDLexWidget yield objects that behave like IDL compound widgets. XOBJVIEW is a top-level base widget with such a "widget object" inside of it.

Another class to take note of is IDLexObjview. This is the class called upon to scale and center the graphics that the user wants to see. Objects of class IDLexObjview are object graphics "views" because their class is derived from IDLgrView. Normally XOBJVIEW creates one of these views and uses it automatically. The user doesn't have to worry about it. It's interesting to note, however, that if you supply one or more IDLexObjviews yourself, XOBJVIEW will use your view or views instead of creating its own. Here is an example showing a single IDLexObjview explicitly created:


	
	
	IDL> oOrb = obj_new('orb', color=[255,0,0])
	IDL> oView = obj_new('IDLexObjview')
	IDL> oView->Add, oOrb
	IDL> xobjview, oView

XOBJVIEW's ability to take such view arguments is an undocumented feature. The feature is undocumented because XOBJVIEW takes liberties with view objects it is given, setting the objects' properties at will and leaving those properties changed. Such furtive behavior is uncharacteristic of XOBJVIEW, which normally tries to display the objects it is given without changing them in any way. (Another reason the feature is undocumented is that all of the IDLex classes are undocumented.)

Why would you want to create your own IDLexObjviews explicitly? One answer is that you can use them anywhere you use a regular IDLgrView. Plus they offer programmatic control over the same rotation, automatic centering, etcetera that you see and experience with XOBJVIEW. In addition, explicitly created IDLexObjViews offer access to functionality not available in the XOBJVIEW GUI interface. For example, I like to create my own IDLexObjviews when I want to add axes to my visualizations or make my visualizations be anisotropic. In the case of axes, XOBJVIEW doesn't give axes any special treatment, but I can tell an explicitly created IDLexObjview that it should give axes special treatment, adjusting them to fit everything else in the view. I do this using the keyword ADJUST_AXES. Continuing here from the previous example:


	
	
	IDL> oAxis0 = obj_new('IDLgrAxis', 0)
	IDL> oAxis1 = obj_new('IDLgrAxis', 1)
	IDL> oWindow = obj_new('IDLgrWindow', retain=2)
	IDL> oView->Add, [oAxis0, oAxis1]
	IDL> oView->Reset, oWindow, /adjust_axes
	IDL> oWindow->Draw, oView

The axes bracket the orb nicely because they have been automatically adjusted (via the ADJUST_AXES keyword) when the view was reset.

You can even add or move items and then readjust axes to fit your changes. Here is an example where the orb has been moved ten units to the right:


	
	
	IDL> oOrb->SetProperty, xcoord_conv=[10,1]
	IDL> oView->Reset, oWindow, /adjust_axes
	IDL> oWindow->Draw, oView

ADJUST_AXES preserves the relative location of axes, so if we add a z-axis located at what is currently the high end of our y-axis, the z-axis will stay in that relative position each time we subsequently adjust. Here is an example:

	
	
	
	IDL> oAxis0->GetProperty, ticklen=ticklen
	IDL> oAxis2 = obj_new('IDLgrAxis', 2, location=[9,1], ticklen=ticklen)
	IDL> oView->Add, oAxis2
	IDL> oView->Reset, oWindow, /adjust_axes
	IDL> oView->Rotate, [0,0,1], 30
	IDL> oView->Rotate, [1,0,0], -60
	IDL> oWindow->Draw, oView

As mentioned above, I sometimes like to set whether an IDLexObjview will be isotropic. "Isotropic" means that a visualization is proportionate in x, y, and z. If you turn off the isotropic property, graphics can stretch to fill up more of the view:


	
	
	IDL> oView->SetProperty, isotropic=0
	IDL> oView->Reset, oWindow
	IDL> oWindow->Draw, oView
	

One detail to note about IDLexObjView is that this class has its 'Add', 'Remove', 'Count' and 'Get' methods overridden. At first glance if you are looking in the code this might seem a bit shocking, but the override is done so as to be consistent with user expectations about how a normal IDLgrView behaves. Since an IDLexObjView is an IDLgrView, it should behave the same as a regular IDLgrView from the user's point of view. Specifically, an IDLexObjView is an IDL_Container that should behave like any other IDL_Container. If the user adds an object at a specified or default position, then the user should be able to get that object from the same position. For example:

	oView->Add, oModel, position=1
	result = oView->Get(position=1)

If the methods were not overridden, the result would be some mysterious thing such as oModel1 (or whatever), which is part of the implementation details inside of the IDLexObjView class. That is why the methods are overridden. Users should be happily unaware of implementation details such as oModel1, oModel2, etc. that are inside of IDLexObjView.

In 2002 I made enhancements to the IDLex code and submitted my changes to Research Systems with the hope that Research Systems might include the changes in a future release of IDL. (Their "incident ID" for this is 126783.) Here is that modified code and notes describing the changes I made. None of the changes I made pertain to documented IDL functionality. They apply in special cases when you are using the undocumented IDLex code.

Home