Enterprise Architect -> Как получить край конечного узла с помощью SQL-запроса к .eap-File (.mdb) - PullRequest
0 голосов
/ 25 марта 2019

Я должен нарисовать некоторые диаграммы советника, используя только файл .eap без установленного советника на сервере. Поэтому я открываю его как MDB-файл через ODBC.

Я знаю, что есть атрибут t_diagramlinks.Geometry (с ребром = {1,2,3,4}) и атрибут t_connector.Start_Edge и атрибут t_connector.End_Edge.

Таблица t_diagramlinks с атрибутом Geometry зависит от диаграммы. Таблица t_connector с атрибутами .Start_Edge и .End_Edge не зависит от диаграммы -> могут быть соединения, которые не были нарисованы на диаграмме.

Я знаю, что SX, SY, EX, EY, равные t_diagramlinks, являются координатами относительно начала каждого узла, который нарисован на диаграмме.

Проблема: EX / EY иногда равен нулю и не рисует конечную линию к краю узла. Я думаю, это как-то связано с положением отпускания мыши.

"Моя интерпретация" ниже - это то, что мой рендерер производит на основе моих предположений.

«Интерпретация EA» - это то, что EA на самом деле рендерит, и что я также хотел бы видеть в моем рендерере.

enter image description here

Вопросы

  • Я использую csv-Value EDGE в t_diagramlinks.Geometry - но где найти это для конечного узла?

  • Для каких целей используются атрибуты Start_Edge и End_Edge в таблица t_connector когда она не зависит от диаграммы?

Ответы [ 2 ]

1 голос
/ 23 апреля 2019

Большое спасибо. Я решил математически рассчитать End-Edge:

End Edgge node

Моя проблема заключалась в том, что я не смог обнаружить конечный край целевого конечного узла в отношении ссылки. Более того, существует 8 различных типов ссылок, которые определяют расположение ссылок. Итак, как сказал Томас, я должен был определить последнюю точку перед конечной точкой. Если это путь, последний узел пути - это точка перед конечной точкой. Если пути нет, начальная точка начальных узлов является последней точкой перед конечной точкой. Но если определен путь и режим соединения установлен в 1, я не могу обработать путь соединения, поскольку свойство Conn_Path содержит настраиваемую строку - но после настройки пользователь выбрал прямую ссылку (он не будет быть удаленным).

Математическое обозначение используется в качестве линейной функции y = m * x + b, и линии описываются 4 прямыми линиями, которые соответствуют краям конечного узла.

Таким образом, вы можете сделать следующий алгоритм:

Page one of the algorithm

enter image description here

Полный алгоритм использует следующий подход:

1.) Определить прямую линию между начальным и конечным узлом (есть 2 особых случая, если линия полностью горизонтальна или вертикально параллельна системе координат)

2.) Создайте прямоугольник, состоящий из четырех прямых линий (2 вертикальные / 2 горизонтальные линии)

3.) Определить пересечение первой прямой с линиями прямоугольников

4.) Исключить точку, которая не состоит из прямоугольника

5.) Определите точку на прямоугольнике с кратчайшим расстоянием => это искомая конечная точка края

Написанный код JavaScript, который я использовал для маршрутизации, выглядит следующим образом:

                //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Erzeuge eine eigene Link-Klasse für das Routing der Pfeile, die von Hand gezogen wurden
// und über spezielle Attribute in der EAP-Datei definiert werden
// Ruft die Superklasse von go.Link im Konstruktor auf
function MultiNodePathLink() {
    go.Link.call(this);
}
go.Diagram.inherit(MultiNodePathLink, go.Link); // Erben von go.Link

// ignores this.routing, this.adjusting, this.corner, this.smoothness, this.curviness
/** @override */
MultiNodePathLink.prototype.computePoints = function () {

    // Die this Referenz ist hier ist ein geerbter ein go.Link. der bei Links
    var startNode = this.fromNode;
    var startNodeX = startNode.location.M;  // X-Koordinate vom Startknoten
    var startNodeY = startNode.location.N; // Y-Koordinate vom Startknoten

    var endNode = this.toNode;
    var endNodeX = endNode.location.M;  // X-Koordinate vom Startknoten
    var endNodeY = endNode.location.N; // Y-Koordinate vom Startknoten

    var startNodeData = startNode.data; // Das sind die Daten
    var endNodeData = endNode.data; // Das sind die Daten

    // Die Link-Daten
    var linkProperties = this.data;
    //** Das Feld Style in [t_diagramlink] bestimmt die Connector-Darstellung  **/
    // http://www.capri-soft.de/blog/?p=2904
    /*
     *  1 = Direct                    Mode=1
     *  2 = Auto Routing              Mode=2
     *  3 = Custom Line               Mode=3
     *  4 = Tree Vertical             Mode=3;TREE=V
     *  5 = Tree Horizontal           Mode=3;TREE=H
     *  6 = Lateral Vertical          Mode=3;TREE=LV
     *  7 = Lateral Horizontal        Mode=3;TREE=LH
     *  8 = Orthogonal Square         Mode=3;TREE=OS
     *  9 = Orthogonal Rounded        Mode=3;TREE=OR
     */
    var styleStringArray = linkProperties.style.split(";");
    var mode = -1;
    var tree = '';
    for (var i = 0; i < styleStringArray.length; i++) {
        if (styleStringArray[i].trim().indexOf('Mode=') > -1) {
            mode = styleStringArray[i].replace('Mode=', '');
        }

        if (styleStringArray[i].trim().indexOf('TREE=') > -1) {
            tree = styleStringArray[i].replace('TREE=', '');
        }
    }



    // In der Tabelle t_diagramlinks in der Freitextspalte "Geometry" wird in einem CSV-String
    // gespeichert, wie der Link letztendlich auf dem Diagram gezogen wurde
    var geometryString = linkProperties.geometry.split(";");
    // SX and SY are relative to the centre of the start object
    var sx = geometryString[0].replace("SX=", "");
    var sy = geometryString[1].replace("SY=", "");
    // EX and EY are relative to the centre of the end object
    var ex = geometryString[2].replace("EX=", "");
    var ey = geometryString[3].replace("EY=", "");

    // SX=-67;SY=-43;EX=-12;EY=-40;EDGE=3;$LLB=;
    // LLT=;LMT=;LMB=CX=30:CY=13:OX=11:OY=-2:HDN=0:BLD=0:ITA=0:UND=0:CLR=-1:ALN=1:DIR=0:ROT=0;
    // LRT=;LRB=;IRHS=;ILHS=;

    // EDGE ranges in value from 1-4, with 1=Top, 2=Right, 3=Bottom, 4=Left (Outgoing Point of the Start Object)
    var edge = geometryString[4].replace("EDGE=", "");

    // Hier beginnt das Custom-Routing
    this.clearPoints();
    if (linkProperties.start_object_name == 'System Verification Test Reports' && linkProperties.end_object_name == 'System test specifications') {
        var test = 'irrsinn';
    }
    // Hier werden die Wege definiert für das gecustomizte Link Routing
    // Geht der Link nach oben oder unten wird die Y-Koordinate des Startknotens genutzt (Weil Orthogonales Routing)
    var startConnX = null;
    var startConnY = null;
    if (edge == 1) { // Ecke oben
        startConnX = Math.abs(startNodeX) + Math.abs((startNode.actualBounds.width / 2) + new Number(sx));
        startConnY = Math.abs(startNodeY);
    }
    else if (edge == 3) { // Ecke unten
        startConnX = Math.abs(startNodeX) + Math.abs((startNode.actualBounds.width / 2) + new Number(sx));
        startConnY = Math.abs(startNodeY) + new Number(startNode.actualBounds.height);
    }
    else if (edge == 2) { // Ecke rechts
        startConnX = Math.abs(startNodeX) + startNode.actualBounds.width;
        startConnY = Math.abs(startNodeY) + Math.abs((startNode.actualBounds.height / 2) - new Number(sy));
    }
    else if (edge == 4) { // Ecke links
        startConnX = new Number(Math.abs(startNodeX));
        startConnY = Math.round(startNodeY) + Math.round((startNode.actualBounds.height / 2) - new Number(sy));
    }
    else {
        alert('Die Edge konnte nicht entdeckt werden! Ist der Geometry String in der EAP Datei richtig?');
    }

    this.addPoint(new go.Point(Math.round(startConnX), Math.round(startConnY)));

    // Abfrage: Gibt es einen letzten Path Punkt?
    var lastPathPunkt=false;
    var lastPathPunktX, lastPathPunktY;

    if (mode != 1)
    {
        // Routing über die Zwischenwege
        if (typeof linkProperties.conn_path !== "undefined" && linkProperties.conn_path !== "") {
            var splittedArray = linkProperties.conn_path.split(";");
            if (splittedArray.length > 1) {
                // Hier ist mindestens ein Wert vorhanden da auch der erste mit Semikolon abgeschlossen wird im Path vom EA
                for (var i = 0; i < splittedArray.length - 1; i++) {
                    var einMittelPunkt = splittedArray[i];
                    var mittelPunktArray = einMittelPunkt.split(":");
                    this.addPoint(new go.Point(Math.abs(new Number(mittelPunktArray[0])), Math.abs(new Number(mittelPunktArray[1]))))
                    lastPathPunktX = Math.abs(new Number(mittelPunktArray[0]));
                    lastPathPunktY = Math.abs(new Number(mittelPunktArray[1]));
                    lastPathPunkt = true;
                }
            }
        }
    }

    // Wenn es keinen Pfad gab,muss der letzte Punkt mit dem Startknoten identisch sein
    if (lastPathPunkt == false) {
        lastPathPunktX = Math.abs(Math.round(startConnX));
        lastPathPunktY = Math.abs(Math.round(startConnY));
    }

    // End-Routing
    // Der Endpunkt in EA in Document Coordinates
    var endConnX = Math.abs(endNodeX) + Math.abs((endNode.actualBounds.width / 2) + new Number(ex));
    var endConnY = Math.abs(endNodeY) + Math.abs((endNode.actualBounds.height / 2) - new Number(ey));

    // Spezialfälle bei horizontalen und vertikalen Linien:
    if (endConnX == lastPathPunktX) {
        // Es liegt eine vertikale Gerade (z.B. von oben nach unten) vor
        this.addPoint(new go.Point(Math.round(lastPathPunktX), Math.round(lastPathPunktY)));
        this.addPoint(new go.Point(Math.round(endConnX), Math.round(endConnY)));

    } else if (endConnY == lastPathPunktY) {
        // Es liegt eine horizontale Gerade (z.B. von rechts nach links) vor
        this.addPoint(new go.Point(Math.round(lastPathPunktX), Math.round(lastPathPunktY)));
        this.addPoint(new go.Point(Math.round(endConnX), Math.round(endConnY)));
    } else {
        // Es ist keine Gerade sondern ein Gerade, die mit y=m*x+b beschrieben werden kann

        // 1.) Gerade zwischen Start- und Endpunkt ermittelnhn
        //      Ye-Ys
        //  m = -----    b=Ys-m*Xs oder b=Ye-m*Xe
        //      Xe-Xs
        var m = (endConnY - lastPathPunktY) / (endConnX - lastPathPunktX);
        var b = lastPathPunktY - m * lastPathPunktX

        // 2.) Ermittlung der horizontalen und vertikalen Geraden des Rechteckes und dem Schnittpunkten
        // Die Geraden, die das Rechteck definieren:
        var rY1 = endNodeY;
        var rY2 = endNodeY + endNode.actualBounds.height;
        var rX1 = endNodeX;
        var rX2 = endNodeX + endNode.actualBounds.width;
        // (rX1, rY1) -zu-> (rX2, rY2)

        // Horizontale Geraden:
        //     y - b
        // x = -----
        //       m


        var lengthToPoint = [];

        var sX1 = (rY1 - b) / m; // S1(sX1|rY1)
        if (sX1 >= rX1 && sX1 <= rX2) {
            // Der Schnittpunkt sX1 ist am Rechteck
            // Distanz: d=SQRT((y2-y1)^2+(x2-x1)^2)
            var dS1 = Math.sqrt(Math.pow(rY1 - lastPathPunktY, 2) + Math.pow(sX1 - lastPathPunktX, 2));

            lengthToPoint.push({
                "distanz": dS1,
                "x": sX1,
                "y": rY1
            });

        }

        var sX2 = (rY2 - b) / m; // S2(sX2|rY2)
        if (sX2 >= rX1 && sX2 <= rX2) {
            // Der Schnittpunkt sX2 ist am Rechteck
            // Distanz: d=SQRT((y2-y1)^2+(x2-x1)^2)
            var dS2 = Math.sqrt(Math.pow(rY2 - lastPathPunktY, 2) + Math.pow(sX2 - lastPathPunktX, 2));

            lengthToPoint.push({
                "distanz": dS2,
                "x": sX2,
                "y": rY2
            });
        }

        // Vertikale Geraden:
        //
        // y = m*x + b

        var sY1 = m * rX1 + b; // S3(rX1|sY1)
        if (sY1 >= rY1 && sY1 <= rY2) {
            // Der Schnittpunkt sY1 ist am Rechteck
            // Distanz: d=SQRT((y2-y1)^2+(x2-x1)^2)
            var dS3 = Math.sqrt(Math.pow(sY1 - lastPathPunktY, 2) + Math.pow(rX1 - lastPathPunktX, 2));

            lengthToPoint.push({
                "distanz": dS3,
                "x": rX1,
                "y": sY1
            });
        }

        var sY2 = m * rX2 + b; // S4(rX2|sY2)
        if (sY2 >= rY1 && sY2 <= rY2) {
            // Der Schnittpunkt sY2 ist am Rechteck
            // Distanz: d=SQRT((y2-y1)^2+(x2-x1)^2)
            var dS4 = Math.sqrt(Math.pow(sY2 - lastPathPunktY, 2) + Math.pow(rX2 - lastPathPunktX, 2));

            lengthToPoint.push({
                "distanz": dS4,
                "x": rX2,
                "y": sY2
            });
        }

        // Sortiere alle Punkte nach Distanz - der mit der kleinsten Entfernung isses
        lengthToPoint.sort(function (a, b) { return a.distanz - b.distanz });

        if (lengthToPoint.length > 0)
        {
            this.addPoint(new go.Point(Math.round(lengthToPoint[0].x), Math.round(lengthToPoint[0].y)));
        }
        else
        {
            this.addPoint(new go.Point(Math.round(lastPathPunktX), Math.round(lastPathPunktY)));
        }


    }

    return true;
};
// end MultiNodePathLink class
1 голос
/ 25 марта 2019

Я использую в t_diagramlinks.Geometry EDGE csv-Value - но где я могу найти это для конечного узла?

Вам нужно использовать Евклид. SX, SY / EX, EY - относительные сдвиги от кратчайшего центрального соединения между начальным и конечным элементом.

Для каких целей используются атрибуты Start_Edge и End_Edge в таблица "t_connector", когда она не зависит от диаграммы?

Они используются для квалифицированных свойств.

Редактировать : подробнее рассказать о вашей основной проблеме. t_diagramlinks.path содержит точки изгиба для соединителя (если указаны). Таким образом, чтобы найти точку, где соединитель действительно соединяется с элементом, вы должны найти ближайший изгиб к этому элементу. Теперь между этим изгибом и серединой элемента у вас будет естественная точка крепления. Относительно этого добавляются SX-Y (/ EX-Y), чтобы сделать вручную смещенную визуализированную точку присоединения.

Вышесказанное идет с зерном соли. Я никогда не проверял мельчайшие нотки, но использовал свой желудок, чтобы увидеть цифры. Я мог бы изучить это подробно, чтобы обновить мою книгу Inside, но не могу обещать.

2nd Edit : Теперь, когда я знаю, что «Моя интерпретация» - это то, что ваш рендерер производит на основе ваших предположений, вот (скорее всего, см. Выше) история. Для отображения коннектора советник будет использовать следующую информацию:

  • координаты кадра двух соединенных элементов
  • вычислено из координат средней точки элементов
  • свойство пути коннектора (если не пустое)
  • ближайшая точка изгиба к соответствующим элементам (если не пустая)
  • коэффициенты сдвига SX-Y и EX-Y для разъема

Начиная от средней точки начального элемента, вы рисуете виртуальную линию либо до ближайшей точки изгиба, либо до середины конечного элемента (если не см. Ниже). Таким образом, вы можете вычислить виртуальную точку присоединения в прямоугольной рамке элемента (даже в сценариях использования есть прямоугольная рамка). Теперь вы сдвигаете эту точку на SX-Y, которая будет (/ должна?) Всегда перемещаться вдоль края рамки элемента. Теперь у вас есть виртуальная точка подключения для начального элемента.

С другой стороны (конечный элемент; мое «разве что» сверху) вы бы сделали аналогичную вещь для вычисления виртуального вложения для конца. Чего я не знаю, так это реального порядка, в котором EA это делает (у меня нет понимания кода). Поэтому, если у вас есть ручные смещения с обеих сторон, расчет даст разные результаты в зависимости от порядка отрисовки виртуального соединения с другой стороной (так: учитывается ли сдвиг на другой стороне или нет). В принципе, я думаю, что вы можете пренебречь, что для 99,9% всех случаев, а в остальном просто не имеет значения шум.

Итак, теперь вы знаете, что к виртуальным конечным точкам вы либо подключаете их напрямую, либо, если путь дан, вы подключаете их через точки изгиба.

Опять же: все с зерном соли. Это просто наблюдение снаружи, но, вероятно, не слишком далеко. Также есть тот факт, что у вас есть разные стили линий со скругленными краями (здесь не учитываются) и более безликие линии (еще больше земли дракона).

...