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:
-
Open (as a model) the Buttons model created by AToM3 (an explanation of
this was given in section 2).
-
Add a new Button, change the name as you please.
-
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:
-
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.
-
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:
-
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.
-
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
Maintained by Juan de Lara.
Last modified 26 July 2002.