Graphical coordinates of a Capella Element inside a Diagram (Node/Edge..)

Hello,
I am able to obtain Capella elements inside variables as Python Objetcs, or as Java objects. The functions of the simplified Api allow for all of that.

When it comes to getting the coordinates of an element inside a diagram, let’s say I have a Logical Component that is placed in the bottom left of an LAB diagram.
I would like to find a way to find it’s coordinates, the coordinates of its center OR of its top left coordinates.
Any method could help.
Even its coordinates compared to another component.
Or just coordinates in general.
Is there any way somehow to obtain this type of informations?
When I check the capella files xml code I see this type of info that looks like coordinates I believe?

Of course finding the size of the whole diagram could be mandatory to compare the coordinates of the Logical component to the whole diagram. So is there a way to find the dimensions of the diagram aswell?

A bonus: would be to find the dimensions of a Logical Component aswell?

Anyway, any help could be great!
Thanks

The XMI you are showing is the GMF notation model. It’s an EMF model just like the Capella model so you could access this information but the Python API is clearly not designed to to this.

In Java you can have a look at org.eclipse.gmf.runtime.notation.Node and the Node.getElement() should return a DDiagramElement from Sirius. Then you could check if the referenced element is your component. Capella provides a utility class ShapeUtil that might be interesting for you.

Thanks for the answer first.
So this is the only way to try to obtain coordinates to our capella elements through Python 4 Capella? (Checking the GMF Notation)
You don’t see any simpler way to get an “indication” of the position of a capella element through P4C somehow?


As for the “ShapeUtil” I found it inside this path:
MycapellaInstallation\plugins\org.polarsys.capella.core.sirius.analysis.source_5.1.0.202106150755\org\polarsys\capella\core\sirius\analysis (I am using Capella 5.1)

I see lot of functions involving “DDiagramElement” as a paramater, from retrieving the nodes to setting the styles. Okay.

I also found lot of X.getElement():

  • DNodeContainer container = (DNodeContainer) currentNode.getElement();
  • for (Object oIte : diagram.getPersistedEdges()) {
    if (oIte instanceof Edge) {
    Edge edgeIte = (Edge) oIte;
    if (edgeIte.getElement() == siriusNode) {…

Not sure where to find : (org.eclipse.gmf.runtime.notation.Node)?
Maybe Github of Capella? Tried to find it but did not succeed.

So To summerize, the idea is to use a PythonObject–> Get the java object of it → ??? Try to find its node (by looking at the org…notation.Node)…?? → Then with the node I obtained, get the DDiagramElement using(Node.getElement()) -->Compare it… No this sound wrong.
Maybe: Get a list of objects → Get their Nodes → Get their DDiagramElement’s → Obtain somehow their referenced element → Compare it with my list of LC’s, Confirm the right LC → Use its DDiagramElement to obtain its coordinates.
Something like that… Sirius Stuff seems so obscure sometimes to be honest.

To get the annotation model you will need to load the .aird file or get the model from the Sirius Session’s ResourceSet. The source code of GMF can be found on github.

An other idea could be using a crossreferencer to navigate Node.element in the opposite direction. Sirius is using GMF for rendering, that’s why only GMF has this information about positions.

Hi again,
You mentioned ShapeUtil being from/in Capella,
So I went searching every plugin of capella and I found out that it could be related MOSTLY to colors but not so much to coordinates?


Every function I see here “seems” to be linked to Colors rather than coordinates.

Maybe there are other functions related to ShapeUtil that could provide coordiantes?

But again all of this is somehow related to Node.getElement() which provides an EMF element that can “point” to one of my Capella Elements, then… you can theoretically use “ShapeUtile” to find its coordinates or something like that.

As for the Node.get… it is probably the function “GetLayout” shown here:

Click

In the end to summarize:

  1. P4C must first find a Node.
  2. Problem: The diagram.get all represented elements → provides only REAL elements (from project tree) and does not provide the NODES. (It is theoretically better like that), I don’t recall another method to obtain the nodes other than eAllContents is there?
  3. When the Node is found, you can use getElement, to find which element in project explorer it is pointing at
  4. Since you know which is the right Element, you can continue and search for the coordinates (whithout leaving the Node item)
  5. You somehow apply (getLayoutConstraint()) to the node
  6. combine (4) and (5) to find the coordinates of a given capella element.

I think I found something helpful org.eclipse.sirius.diagram.ui.business.api.view.SiriusGMFHelper that allows to get the View or the Node from a DDiagramElement (specific DRepresentationElement for diagrams). Then you can navigate from DDiagramElement filter on the CapellaElement you want then get the Node and its Bounds.

1 Like

Not saying this is the nicest way to do it, but something like this should work:

# gets the SystemEngineering and print its name
se = model.get_system_engineering()

# (hardcoded) gets a DRepresentation Descriptor for the first diagram of the first function....
diagram = se.get_all_contents_by_type(SystemFunction)[1].get_representing_diagrams()[0]
#gets the representation
representation = diagram.get_java_object().getRepresentation()

diagramNodes = e_all_contents(representation.getOwnedAnnotationEntries()[0].getData())

model.start_transaction()
try:
    for node in diagramNodes:
        if str(EObject.get_class(node)) == "<class '__main__.Node'>":
            elementLayout = node.getLayoutConstraint()
            if str(elementLayout.getClass()) == "class org.eclipse.gmf.runtime.notation.impl.BoundsImpl":          
#                print("getHeight: " + str(elementLayout.getHeight()))
#                print("getWidth: " + str(elementLayout.getWidth()))
#                print("getX: " + str(elementLayout.getX()))
#                print("getY: " + str(elementLayout.getY()))
                elementLayout.setHeight(15)
                elementLayout.setWidth(15)
                elementLayout.setX(15)
                elementLayout.setY(15)
            elif str(elementLayout.getClass()) == "class org.eclipse.gmf.runtime.notation.impl.LocationImpl":
                pass
            else:
                pass
except:
    # if something went wrong we rollback the transaction
    model.rollback_transaction()
    raise
else:
    # if everything is ok we commit the transaction
    model.commit_transaction()
 
model.save()
2 Likes

It’s awesome because I started to pick up on the GMF structure by playing with acceleo query langage, I actually found the location class and also the attributes, but was not sure about the functions in P4C, this “owned” term sure does appear a lot in Capella. Happy to recognize some functions for once, I have always felt these appeared from nowhere and had a hard time usually.

I just tested the script, it seems to be working fine, one little error because of an “None” item but that’s not a problem it can be resolved easily.

My observation is that Diagrams in Capella have no “dimensions” I believe? They just expand and retract depending on the biggest “x” and “y” of all elements withing a given diagram, not sure. Thanks a lot to both!

Glad that it helped - I think I have heard that the diagrams do not have any dimension for the reason you said.
Out of curiosity, what is your intent with modifying the node coordinates?

I will send you a PM later to answer you

Hello everyone,
I was very glad to find this post, since I am trying to achieve the same exact thing, in hopes of finding a way to determine the order in which SequenceMessages and StateFragments occur in an ExchangeScenario.

However, I couldn’t get this script working yet. Error:
AttributeError: 'Node' object has no attribute 'getLayoutConstraint'
In fact, the class “Node” does not have a method like that. I searched for it in different files but had no luck.

Can anyone think of a reason why it isn’t working?
Or maybe someone has a better idea regarding how to determine the order in which ES elements occur?

Many thanks

I think a better solution is probably to look into the “Invoked Messages” result in the semantic browser when selecting the Exchange scenario diagrams, it looks like it is giving you the messages in the right order.

Stephane

@StephaneLacrampe solution is probably better, but the org.eclipse.gmf.runtime.notation.Node class has a method getLayoutConstraint().

You can try something like:

diagram = ... # some Diagram from the Python4Capella API
for representation_element in diagram.get_java_object().getRepresentation().getOwnedRepresentationElements()
    # you need some checks here to make sure you are on a Node and not an Edge
    node = org.eclipse.sirius.diagram.ui.business.api.view.SiriusGMFHelper(representation_element)
    node.getLayoutConstraint()

You can also check the Java class of your object node:

print(node.getClass().getCanonicalName())

If should output:

org.eclipse.gmf.runtime.notation.Node