Programming

<<[The ATOM3 class]  ::: 

8. Debugging and common programming patterns

If the objects in your meta-models have many pre and post conditions, or you are building a complex graph-grammar, you may need some debugging before it works correctly. You can use the console for this purpose. In this console you can evaluate any Python expression, which is evaluated as if it were inside the main ATOM3 class instance. Figure 1 shows an example of this:


Figure 1: Using the console to debug a meta-model

In the previous figure we have retrieved all the objects of type 'Block' there are currently in the model (that is, in the listNodes dictionary of the ATOM3 class' attribute ASGroot).

Other interesting information regarding graphics can be found in the static information of VisualObj. For example VisualObj.EntityList gives us the list of all the graphEntity objects currently drawn in the canvas. With VisualObj.LinkList we obtain similar information for graphLinks. The VisualObj.Tag2ObjMap dictionary gives us more detailed information, regarding all center, segment and link objects in graphLinks, as well as graphEntity objects.

8.1 Common programming patterns

In this section we'll comment common patterns that arise when programming AToM3 constraints with Python.

8.1.1. Adding a new button to the Buttons model to execute a graph grammar

Once you have developed a graph grammar, you may want to create a button in your meta-model's user interface to execute it (instead going to the menus, searching for the graph grammar, etc.) Also it's much more convenient for the final users of your formalism. The way to do this is:
  1. Open (as a model) the Buttons model created by AToM3 (an explanation of this was given in section 2).
  2. Add a new Button, change the name as you please.
  3. Edit the "Actions" field, here you have to type the Python code to be executed when the button is clicked. The following is an example of this:
      # The parameters of this method are:
      #   - wherex
      #   - wherey
      from PNSimulator import PNSimulator
      from GraphRewritingSys import GraphRewritingSys
      self.grs = GraphRewritingSys(self, [PNSimulator(self)], self.ASGroot)
      self.grs.evaluate(1, 0, self.grs.SEQ_MANUAL)
    Information about the GraphRewritingSys object can be found in section 6.

8.1.2. Creating a new node in the model from Python

Sometimes, in actions specified with Python, you'd like to create new objects. The easiest way to do this is by calling the methods which are located in the file named <your-meta-model-name>_MM.py (more information on this can be found in section 2). The methods that create the objects are called createNew<object>, and have the following signature: createNew<object>(self, wherex, wherey, screenCoordinates = 1).

So if you want to create an object inside a constraint, all you have to do is:

  1. obtain a pointer to the ATOM3 class instance. If the constraint is located inside an ASGNode (or an ASG), the this instance is in the attribute self.parent (see section 1.1). If you are in a GGrule instance, in the condition, in the action, or the "Specify" section in a node in a RHS. Then as explained in section 6, one of the parameters these methods receive is called atom3i, which is the instance you need.
  2. Invoke the createNew<object> on this instance with the appropriate parameters. If you are specifying canvas coordinates, remember to set the screenCoordinates parameter to 0.

8.1.3. Connecting  two nodes in the model from Python

For this task, the easiest way is to call drawConnections. This is a method of the ATOM3 class which was explained in section 7. The method takes an aribtrary number of tuples with the information of the objects to be connected. Usually, the tuples have 2 elements, with the pointer to the semantic objects (instances of a class child of ASGNode) to be connected. You can also add additional elements, such as a list with the coordinates of the point's connection (which can be a multi-point connections), and a flag to indicate if the connection should be smoothed.

So if you want to connect to objects, all you have to do is:

  1. obtain a pointer to the ATOM3 class instance. If the constraint is located inside an ASGNode (or an ASG), the this instance is in the attribute self.parent. If you are in a GGrule instance, in the condition, in the action, or the "Specify" section in a node in a RHS. Then as explained in section 6, one of the parameters these methods receive is called atom3i, which is the instance you need.
  2. Invoke the drawConnections method on this instance with the appropriate parameters.

8.1.4. Accesing the node with a certain label in a graph grammar rule

From GGrule objects, you can access nodes with a certain label (an integer), either in the LHS or in the RHS graphs. For example, suppose you want to access the node with label 3 in the LHS, you'd have to type:
    self.LHS.nodeWithLabel(3).

But most of the times, you won't want this node, but the node in the host graph which made a match with this node. For this purpose you'd have to type:

    node = self.getMatched(graphID, self.LHS.nodeWithLabel(3))

The meaning of the graphID parameter was explained in the Graph Grammars section.

8.1.5. Iterating on all the nodes of a model

You can iterate on all the nodes of a model by accessing the listNodes dictionary of the ASG object which contains the model. There's a pointer to this object in the ASGroot attribute of the ATOM3 class. So, supposing you have an instance of ATOM3 (the way to get an instance was explained in section 8.1.2) lets say called atom3i, this could be the code you could use to iterate on all the nodes in your model:
for mtype in atom3i.ASGroot.listNodes.keys():
  for node in atom3i.ASGroot.listNodes[mtype]
     # here you can do something with node

<<[The ATOM3 class]  :::



Maintained by Juan de Lara. Last modified 26 July 2002.