Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The transformation is mostly written in Xtend. Its entry point is the PtolemyDiagramSynthesis class, which is registered with KLighD for the visualization of MOML models. It triggers the three different stages of the transformation:

Image Added

  1. The basic transformation. This is what turns a given MOML model into a KGraph model.
  2. An optimization step. A direct transformation of the MOML model doesn't give the best results, which makes this postprocessing step necessary.
  3. The visualization. This step adds the KRendering information necessary for KLighD to actually display the model.

It would certainly be possible – and perhaps even faster – to combine these stages into one. Doing this, however, would result in code that only John Carmack would understand. And even he would curse reading it. Who wouldn't.

Generating the Basic KGraph Model

...

The basic KGraph model is generated by turning all entities and relations into nodes, all ports into... well, ports, and all links into edges. The logic for all of this is implemented in the Ptolemy2KGraphTransformation class and is actually a bit more complex than we just made it sound.

While the model lists a number of entities that are instances of a given actor class, it usually doesn't contain any information about the ports this kind of actor has. To work around this, the transformation tries to use our Ptolemy library to instantiate the actor and query it for its ports. If this succeeds, we add the ports to the actor's representation in the KGraph model and annotate them with information about whether they are input or output ports. If it doesn't – which happens when our Ptolemy library doesn't contain the actor – we add ports to the actor as they are referenced by the links incident to them. In this case, we don't know whether a port is an input port or an output port. Deriving this information is actually (the hardest) part of the next stage.

Just about everything in Ptolemy can have properties. Even properties can have further properties. These properties carry important semantic information that someone browsing the model would want to know, so we copy them into the KGraph for later visualization.

Optimizing the KGraph Model

...

Being the most complex stage, the optimization is necessary for the model to be properly displayed. The code can be found in the Ptolemy2KGraphOptimization class and solves the following problems:

  1. Infer edge directions. Links in Ptolemy are undirected, while edges in the KGraph metamodel are directed. Our layout algorithms, too, assume directed input graphs and emphasize the flow of data. This requires us to infer the correct direction of edges, which is a hard thing to do and doesn't always give correct results. We use a heuristic that first fixes the direction of edges connected to ports that are known to be either input ports or output ports. Going from there, we try to infer the direction of further edges. For example, if a relation has only two incident edges of which one has a known direction, the direction of the second edge is easy to infer. If this second edge goes into a port of unknown type, we can safely assume the port to be an input port and then infer the direction of other edges incident to the port. This system starts to give wrong results once we have many ports of unknown type.
  2. Remove relation vertices. In Ptolemy, all links connect either two relations, or one port and one relation. If a relation only connects two ports, we can replace it by a simple edge, which improves layout and clarity. Since our main layout algorithm, KLay Layered, supports routing hyperedges (edges that connect more than two ports), we can even go a step further: for each relation, we collect the input ports and the output ports it connects. We then connect each input port to each output port directly, thereby removing the relation.
  3. Remove ports from states of modal models. States don't need dedicated connection points since transitions between states don't model the flow of data, but the flow of control from one state to the next.
  4. Convert certain properties to dedicated nodes. Each Ptolemy model has a director that specifies the model of computation to use when executing the model. In Ptolemy, the director is drawn as a green rectangle, very much like a node. In the model, however, the director is a property of the model entity and thus wasn't transformed into a node in the KGraph during the first stage. Also, each model can have parameters also saved as properties. We collect the parameters and turn them into a node that can display them later.
  5. Extract annotations from the model. In Ptolemy, models can be annotated (in programming languages, annotations would be comments; if you are a programmer and have no idea what comments are, you haven't found the right field of work for you yet). The text of annotations is sometimes a simple property of the annotation, in which case visualizing it is straightforward. Often enough, however, the text is specified as an SVG image. This is a problem because the SVG metamodel is not part of the MOML metamodel, which in turn causes the EMF parser that loads the model to panic. We thus wrote code that finds such SVG images and tries to extract the annotation text from them. This usually works.

Adding Rendering Information to the KGraph Model

...

If we fed the KGraph coming out of stage 2 into KLighD, it wouldn't look at all like a Ptolemy model – if anything was displayed at all. For KLighD to know how to render our model, we need to attach KRendering information to the nodes, ports, and edges. The final stage, implemented in the Ptolemy2GraphVisualization class, adds these information. The implementation is actually very simple: for each entity, a big switch statement decides what kind of rendering the entity requires and delegates to a corresponding method. The method then adds layout information to the entity and delegates the creation of the actual KRenderings to another method defined in the KRenderingFigureProvider class. Then, the entity's ports and outgoing edges are treated similarly. Finally, labels and tool tips are handled.

Only one detail deserves some more explanation: how we get our hands at how entities are rendered in Ptolemy. This is done through a mechanism similar to what we already used in the first stage: we simply instantiate the entities using our Ptolemy library, ask Ptolemy to render them, and convert the rendering information into something KLighD supports. This can either be SVG code (if the rendering was originally specified as an SVG image) or a bitmap image. If an actor cannot be instantiated, we have no rendering information and display the actor as a simple rectangle with a black border and white background.