Giter Site home page Giter Site logo

Comments (3)

afdia avatar afdia commented on June 12, 2024 1

Unfortunately it's a bit complicated, but here are some basics:

  1. you should enable the grid and developer mode to track the coordinates/behavior easier
  2. the coordinates x y w h show where any element is placed and how width and high it is (visible blue border when dev mode is active). This is the same for all elements (classes, relations, ...)
  3. the coordinates change if the zoomlevel change (at 100% zoom its declared in 10px spaces).
  4. The shown grid changes according to the zoom, so at 80% zoom the grid is shown every 8px, at 100% it's at every 10px
  5. the additional_attributes are always stored as if the diagram was at 100% zoom (so 10px steps) and they contain coordinates of relation points in the format x1,y1,x2,y2,... so <additional_attributes>10.0;10.0;170.0;10.0</additional_attributes> means there is a point at 10/10 and a point at 170/10. The upper left corner of the relation element (blue box) is considered postion 0/0, so the example would look like this (the arrow is 1 grid down and 1 right from the upper left border, therefore 10/10. the other end is at 17 grid positions to the right and 1 down):
    grafik

So as you see there is just positional information stored but no "connections". All of it is calculated on the fly for sticking behavior.

You can also check out the class https://github.com/umlet/umlet/blob/master/umlet-swing/src/main/java/com/baselet/element/old/element/Relation.java and search for code which handles sticking of relation ends to element borders and follow the Java code from there

from umlet.

uodedeoglu avatar uodedeoglu commented on June 12, 2024

Thank you for your detailed answer. I'll get to work and inspect the source code you provided. If I succed i'll share my implementation here as well.

from umlet.

uodedeoglu avatar uodedeoglu commented on June 12, 2024

I managed to get it working following your basic ideas, hopefully it will be useful for others in future.

Script at the end of the comment does the following;

  • takes .uxf file as input with line (you can move it into an arg for whole script if you like to)
    domtree = xml.dom.minidom.parse("new.uxf")
  • lists relations as text input following the "[Source Concept] - Relation - [Target Concept]" format.
  • I also interpret the relation tag using my own convention where label (panel_attribute text node) follows
    lt=<<-\n{source_cardinality},{verb label etc},{target_cardinality},({preposition}) format, so if you need something else for your task, you need to alter that part.

I tested with a extensive design document, but I'll just share it with a toy example for privacy concerns here.

Script generates following output:

Example Output

Driver 140,240,0,30 [drive : lt=<. 40,20,10,10,150, 10] Car 0,100,0,30               
Car 0,100,0,30 [belong : lt=<. 20,20,190,10,10, 10] Driver 140,240,0,30

using the uxf file

Example Input Diagram

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<diagram program="umlet" version="15.1">
  <zoom_level>10</zoom_level>
  <element>
    <id>UMLClass</id>
    <coordinates>
      <x>0</x>
      <y>0</y>
      <w>100</w>
      <h>30</h>
    </coordinates>
    <panel_attributes>Car</panel_attributes>
    <additional_attributes/>
  </element>
  <element>
    <id>UMLClass</id>
    <coordinates>
      <x>140</x>
      <y>0</y>
      <w>100</w>
      <h>30</h>
    </coordinates>
    <panel_attributes>Driver</panel_attributes>
    <additional_attributes/>
  </element>
  <element>
    <id>Relation</id>
    <coordinates>
      <x>40</x>
      <y>20</y>
      <w>170</w>
      <h>90</h>
    </coordinates>
    <panel_attributes>lt=&lt;.
1*,drive,1*</panel_attributes>
    <additional_attributes>10.0;10.0;80.0;70.0;150.0;10.0</additional_attributes>
  </element>
  <element>
    <id>Relation</id>
    <coordinates>
      <x>20</x>
      <y>20</y>
      <w>220</w>
      <h>150</h>
    </coordinates>
    <panel_attributes>lt=&lt;.
1,belong,1,(to)</panel_attributes>
    <additional_attributes>190.0;10.0;100.0;130.0;10.0;10.0</additional_attributes>
  </element>
</diagram>

Script

import xml.dom.minidom


class ConceptXMLElement:
    def __init__(self, kwargs):
        self.label = kwargs[0]
        self.xs = kwargs[1]
        self.xe = kwargs[2]
        self.ys = kwargs[3]
        self.ye = kwargs[4]

    def __str__(self):
        concept_str = self.label.replace('\n', "")
        concept_str = concept_str.replace('\t', "").lstrip(' ').rstrip(' ')
        concept_str += " " + str(self.xs) + "," + str(self.xe)
        concept_str += "," + str(self.ys) + "," + str(self.ye)

        return concept_str


class RelationXMLElement:
    def __init__(self, kwargs):
        self.label = kwargs[0]
        self.xs = kwargs[1]
        self.ys = kwargs[2]
        self.first_point_x = kwargs[3]
        self.first_point_y = kwargs[4]
        self.last_point_x = kwargs[5]
        self.last_point_y = kwargs[6]
        self.relType = kwargs[7]

    def __str__(self):
        relation_string = "[" + self.label + " : " + self.relType
        relation_string += f" {self.xs},{self.ys},{self.first_point_x}"
        relation_string += f",{self.first_point_y},{self.last_point_x}"
        relation_string += f", {self.last_point_y}" + "]"
        
        return relation_string


domtree = xml.dom.minidom.parse("new.uxf")
group = domtree.documentElement

elements = group.getElementsByTagName("element")

concepts = []
relations = []

for el in elements:
    if el.childNodes[1].firstChild.nodeValue == "UMLClass":
        label = el.childNodes[5].firstChild.nodeValue
        xs = int(el.childNodes[3].childNodes[1].firstChild.nodeValue)
        xe = xs + int(el.childNodes[3].childNodes[5].firstChild.nodeValue)
        ys = int(el.childNodes[3].childNodes[3].firstChild.nodeValue)
        ye = ys + int(el.childNodes[3].childNodes[7].firstChild.nodeValue)

        # print(label, xs, xe, ys, ye)
        concepts.append(ConceptXMLElement([label.strip('\n'), xs, xe, ys, ye]))

for el in elements:
    if el.childNodes[1].firstChild.nodeValue == "Relation":
        label = el.childNodes[5].firstChild.nodeValue
        xs = int(float(el.childNodes[3].childNodes[1].firstChild.nodeValue))
        ys = int(float(el.childNodes[3].childNodes[3].firstChild.nodeValue))
        first_point_x = int(float(el.childNodes[7].childNodes[0].nodeValue.
                                  split(';')[0]))
        first_point_y = int(float(el.childNodes[7].childNodes[0].nodeValue.
                                  split(';')[1]))
        last_point_x = int(float(el.childNodes[7].childNodes[0].nodeValue.
                                 split(';')[-2]))
        last_point_y = int(float(el.childNodes[7].childNodes[0].nodeValue.
                                 split(';')[-1]))
        relType = label.split('\n')[0]
        relType.strip(' ')
        relType.strip('\t')
        if relType == "<<-":
            relType = "Relation"
        elif relType == "<<<<-":
            relType = "Aggregation"
        elif relType == "<<." or relType == "<.":
            relType = "Realization"

        # print(label, xs, xe, ys, ye, relType)
        if len(",".join(label.split('\n')[1:]).split(',')) > 1:
            relations.append(RelationXMLElement(
                [",".join(label.split('\n')[1:]).split(',')[1].strip('\t').
                 lstrip(' ').rstrip(' '),
                 xs, ys, first_point_x, first_point_y, last_point_x,
                 last_point_y, relType]))
        else:
            relations.append(RelationXMLElement(
                [label.split('\n')[1].replace('\t', "").lstrip(' ').
                 rstrip(' '), xs, ys, first_point_x, first_point_y,
                 last_point_x, last_point_y, relType]))

for rel in relations:
    source = None
    target = None
    for con in concepts:
        if (rel.xs + rel.first_point_x >= con.xs and
                con.xe >= rel.xs + rel.first_point_x and
                rel.ys + rel.first_point_y >= con.ys and
                rel.ys + rel.first_point_y <= con.ye):
            target = con
            break
    for con in concepts:
        if (rel.xs + rel.last_point_x >= con.xs and
                con.xe >= rel.xs + rel.last_point_x and
                rel.ys + rel.last_point_y >= con.ys and
                rel.ys + rel.last_point_y <= con.ye and
                target != con):
            source = con
            break
    if source is not None and target is not None:
        print(source, rel, target)
    else:
        print("Fail: ", source, rel, target)

from umlet.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.