next up previous contents
Next: Specifying a Graph Via Up: The Graphical Interface to Previous: run.c

Run Time Results: Manual Graph Creation

We start the program by typing

graphshared

A window then pops up which almost has the look of Figure  5.1. This window shows two slider bars at the bottom; one labeled SCALE FACTOR and the other ROTATION ANGLE. At start up, these are not visible. There is a small square on the far right of the window you have just created. Grab that with your mouse and pull up while holding the mouse button down and you will begin to see these slide bars. The picture you see in Figure  5.1 is what you get after you have moved that square up to the point where the sliders are nicely visible.


  
Figure 5.1: Graph Startup Window
\begin{figure}
\centerline{\psfig{figure=/home/peterson/books/graphs/drawings/start.ps,height=4.0in}}
\end{figure}

Next, click on the button Draw Graph Object. This calls the function run.c which implements our graph object.

Let's look at this code a little at a time:

#include "simulation.h"

void run(Widget w,XtPointer client_data,XtPointer call_data)
{
  XmPushButtonCallbackStruct *P = (XmPushButtonCallbackStruct *)call_data;
  application_data *T = (application_data *)client_data;
  Vertex center_in,center;
  Display *display = T->display;
  Drawable drawable = T->drawable;
  Pixmap pixmap1 = T->pixmap;
  Pixmap pixmap2 = T->pixmap2;
  GC gc = T->gc;

The function run(Widget w,XtPointer client_data,XtPointer call_data) is an example of a callback function in the X Window system. These always have the prototype shown here. The data type XtPointer is a catch-all type which is the union of many data types; essentially any datum which has size less than 4 bytes will work. However, exactly what type of data it is must be set by a cast to the proper data type after you enter the function. So in the fragment above, the data XtPointer client_data is cast to application_data and XtPointer call_data is cast to XmPushButtonCallbackStruct because run is a callback associated with a PushButton.

In the main program sim.c, the callback is registered with this line of code:

  XtAddCallback(wbutton[0],XmNactivateCallback,run,&PDATA);

The function run is now registered as the function which will be called by button 0 ( wbutton[0] is the widget for button 0 which earlier in sim.c was given the label "Draw Graph Object"). We also grab some data from the application_data structure for ease of use.

Now instantiate a graph object with the following construct call. In the header file simulation.h, the application_data structure has a data field T which is set to Graph *T. Hence T->T denotes the pointer to the graph object.

  if(T->T==NULL){
    printf("Building the XGraph object.\n");
    T->T = new Graph(T->radius,T->center,        //node circle
                     T->separation,
                     T->foreground,              //fg
                     T->background,              //bg
                     T->pParts[0]->pixel,        //fill
                     T->pParts[1]->pixel,        //border
                     T->display,                 //graphics
                     T->drawable,
                     T->pixmap,
                     T->pixmap2,
                     T->gc);

Note that all of the graphical information needed to build *(T->T) was initialized in the main file sim.c.

Next, we exercise some of the methods of the graph class just to see how it works. We use the overloaded cin operator to build a node. We are asked to enter a termination symbol (we choose Z) and then we enter an ascii name for a node, hit enter, enter another ascii name if we wish, hit enter and continue until we want to terminate. At that point we type Z and the node creation process stops. We then add more nodes and edges and so forth until we have created a small graph object.

                             
   Node T2;
   cout << "Input the Node:" << endl;
   cin >> T2;
   cout << "Node is " << T2 << endl;
   cout << "Node name is " << T2.name() << endl;
    
   Gnode *n1 = T->T->addNode("Quinn",40.0,200.0);
   Gnode *n2 = T->T->addNode("Qaitlin",120.0,100.0);
   Gnode *n3 = T->T->addNode("Pauli",120.0,200.0);
   Gnode *n4 = T->T->addNode(T2.name(),120.0,300.0);
   
   T->T->addEdge(n2,n1,4.0);
   T->T->addEdge(n1,n3,5.0);
   T->T->addEdge(n3,n2,1.0);
   
   T->T->addNode("Jim",280.0,100.0);
   T->T->addNode("Clive",280.0,300.0);
   
   T->T->addEdge(T->T->findNode("Qaitlin"),T->T->findNode("Jim"),6.0);
   T->T->addEdge(T->T->findNode("Pauli"),T->T->findNode("Clive"),3.0);
   T->T->addEdge(T->T->findNode("Pauli"),T->T->findNode("Jim"),4.5);
   T->T->addEdge(T->T->findNode("Quinn"),T->T->findNode(T2.name()),14.5);   
   T->T->addEdge(T->T->findNode("Pauli"),T->T->findNode("Quinn"),3.5);
   T->T->addEdge(T->T->findNode("Pauli"),T->T->findNode("Pauli"),14.5);   
   }

Next we use the overloaded cout operator to output the ascii version of the graph object.

   
  cout << T->T << endl;

Finally, we initialize the pixmaps, pixmap and pixmap2 for use and draw the object.

 
  //set up pixmaps and compute image
  T->T->erase(T->pixmap);
  T->T->draw(T->pixmap);
  T->T->erase(T->pixmap2);
  T->T->draw(T->pixmap2);
  image(w,T);
}

Then after entering data like we did before in the sample run without the graphical interfaxce, we see this keyboard input and output in the X Window where we started graphshared.

Building the XGraph object.
Input the Node:
Please enter the character that will terminate the input string you want to use for a name
Z
Now enter the name you want to use for the node:
Daisy
Z
Node is Daisy

Node name is Daisy
 
Graph: 
Nodes: 
  Clive  Jim  Clive  Pauli  Qaitlin  Quinn
  Edges:  Pauli-----(14.5)---> Pauli
          Pauli-----(3.5)---> Quinn
         Quinn-----(14.5)---> Clive
          Pauli-----(4.5)---> Jim
          Pauli-----(3)---> Clive
          Qaitlin-----(6)---> Jim
          Pauli-----(1)---> Qaitlin
          Quinn-----(5)---> Pauli
          Qaitlin-----(4)---> Quinn
End Graph

This generates Figure  5.2:


  
Figure 5.2: A Graph Object
\begin{figure}
\centerline{\psfig{figure=/home/peterson/books/graphs/drawings/object1.ps,height=4.0in}}
\end{figure}

Next, look at the slider bar called SCALE FACTOR. This slide goes from 0 to 2 and represents scaling the object to 0 times its present size to doubling its size. The slide code is actually hard wired to prevent shrinkage below 0.85 and expansion above 1.25 because the object changes too much for our presentation purposes otherwise. Now to get started, position the mouse button at the point on the slide you want (the middle is 1.0 or no change) and see what happens. A snapshot of our fiddling with shrinking the object is shown in Figure  5.3. You can also just grab the slide bar control ( a double rectangle with a vertical bar through it ) and slide the control, but if you do that the object changes very rapidly!


  
Figure 5.3: A Scaled Graph
\begin{figure}
\centerline{\psfig{figure=/home/peterson/books/graphs/drawings/scaled.ps,height=4.0in}}
\end{figure}

We can do similar things to rotate the graph by using the slider titled ROTATION ANGLE. First, click on the button labeled Rotation Point and then position your mouse cursor at the point in the drawing area that you want to use as the axis around which the graph object will rotate. The move your mouse cursor to a point on the rotation slide bar and click to pick a rotation angle. A sample is shown in Figure  5.4.


  
Figure 5.4: A Rotated Graph
\begin{figure}
\centerline{\psfig{figure=/home/peterson/books/graphs/drawings/rotated.ps,height=4.0in}}
\end{figure}

Similar things are done to generate a translated object. We click on the button Translation Point and position our cursor to pick a point the graph object should translate to. The nodes of the graph have (x, y) positions which are averaged to give us what we call the graph center. Translation moves the graph center to the newly chosen point given by the clicking of the mouse in the drawing area. Note you can continue to move the object around by simply clicking the mouse cursor in the drawing area as often as you like as the callback function for translation is active and will remain so until another button is pushed. A sample translation image is given in Figure  5.5.


  
Figure 5.5: A Translated Graph
\begin{figure}
\centerline{\psfig{figure=/home/peterson/books/graphs/drawings/translate.ps,height=4.0in}}
\end{figure}

Finally, we can choose colors of the nodes, node boundaries, edges and edge boundaries by clicking on the button labeled Color Choice. This generates a popup window which has slide bars for setting the Red, Green and Blue components of a Read/Write Pixel set aside for our use for the 4 choices mentioned above. The initial popup is shown in Figure  5.6. If you position the popup color choice window appropriately and resize as needed, you will be able to watch the graph object colors change as you move the slide bars for Red, Green and Blue around in the color choice popup.


  
Figure 5.6: The Color Choice Popup
\begin{figure}
\centerline{\psfig{figure=/home/peterson/books/graphs/drawings/popup.ps,height=3.5in}}
\end{figure}


next up previous contents
Next: Specifying a Graph Via Up: The Graphical Interface to Previous: run.c
Jim Peterson
1999-05-17