Enterprise Architect -> 如何使用对 .eap 文件 (.mdb) 的 SQL 查询获取端节点的边缘
Enterprise Architect -> How to get the edge of the end node using a SQL Query on the .eap-File (.mdb)
我必须在服务器上没有安装 EA 的情况下仅使用 .eap 文件绘制一些 EA 图。所以我通过 ODBC 将其作为 MDB 文件打开。
我知道有属性 t_diagramlinks.Geometry
(边={1,2,3,4})和属性 t_connector.Start_Edge
以及属性 t_connector.End_Edge
。
具有属性 Geometry
的 table t_diagramlinks
依赖于图表。
具有属性 .Start_Edge
和 .End_Edge
的 table t_connector
不依赖于图 --> 可能存在未在图上绘制的连接。
我知道t_diagramlinks
的SX、SY、EX、EY是相对于绘制在图上的每个节点的原点的坐标。
问题:EX / EY 有时为零并且没有将结束线绘制到节点的边缘。估计跟鼠标释放位置有关
"My Interpretation" 下面是我的渲染器根据我的假设生成的结果。
"EA Interpretation" 是 EA 实际渲染的内容,我也希望在我的渲染器中看到它。
问题
我在 t_diagramlinks.Geometry
中使用 csv-Value EDGE - 但是在哪里
我要为结束节点找到这个吗?
为了什么目的,属性 Start_Edge 和 End_Edge 在
table t_connector
何时不依赖图表?
I am using in t_diagramlinks.Geometry the csv-Value EDGE - but where
do i find this for the end node?
您需要使用 Euclide。 SX,SY/EX,EY 是起始元素和结束元素之间最短中心连接的相对位移。
For which purpose are the attributes Start_Edge an End_Edge in the
table "t_connector" when it is not diagram-dependend?
它们用于合格的属性。
编辑:详细说明您的基本问题。 t_diagramlinks.path
保存连接器的弯曲点(如果指定)。因此,为了找到连接器实际连接元素的点,您必须找到离该元素最近的弯曲点。现在在这个弯曲和元素的中间之间你将有一个 natural 附着点。相对于添加 SX-Y (/EX-Y) 以制作手动移动的渲染附着点。
以上内容有保留意见。我从来没有核实过细节,但看到这些数字就用了我的胃。我可能会详细研究以更新我的内幕书,但不能保证。
第二次编辑:现在我知道 "My Interpretation" 是您的渲染器根据您的假设生成的内容,这是(最有可能;见上文)的故事。为了呈现连接器,EA 将使用以下信息:
- 两个连通元素的坐标系
- 根据元素的中点坐标计算
- 连接器的路径属性(如果不为空)
- 离相关元素最近的弯曲点(如果不为空)
- 连接器的偏移因子 SX-Y 和 EX-Y
从起始元素的中点开始,绘制一条虚拟线到最近的弯曲点或结束元素的中间(除非见下文)。这样你就可以在元素的矩形框架上计算虚拟附着点(即使用例有一个矩形框架)。现在你将那个点移动 SX-Y,这将(/应该?)总是沿着元素框架的边缘移动。现在您有了起始元素的虚拟附着点。
在另一边(结束元素;我的 "unless" 从上面)你会做类似的事情来计算结束的虚拟附件。我不知道 EA 这样做的真正顺序(我没有代码洞察力)。因此,如果您在两侧都有手动偏移,则计算将根据将虚拟连接绘制到另一侧的顺序给出不同的结果(因此:是否尊重另一侧的偏移)。基本上我认为你可以忽略 99.9% 的所有情况,其余的只是无关紧要的噪音。
所以现在你知道虚拟端点了,你要么直接连接它们,要么,如果给定路径,你通过弯曲点连接它们。
再说一遍:全都持保留意见。这只是从外面观察,但可能不会太远。还有一个事实是你有不同的线条样式,圆边(这里没有考虑)和贝塞尔线(甚至更多的龙之地)。
非常感谢。我选择用数学方法计算 End-Edge:
我的问题是,我无法在 link 关系上检测到目标端节点的结束边缘。此外还有 8 种不同的 link 类型,它们决定了 link 的布局。因此,正如 Thomas 提到的,我必须检测终点之前的最后一点。如果是路径,则路径的最后一个节点是端点之前的点。如果没有路径,则 startnodes 起点是终点之前的最后一个点。但是,如果定义了路径并且 link 模式已设置为 1,我可能无法处理连接路径,因为 Conn_Path 属性 包含自定义行 - 但在自定义之后用户已选择直接 link(不会被删除)。
后面的数学用的是线性函数y=m*x+b,直线用4条适合端节点边缘的直线描述。
所以你可以做如下算法:
完整的算法使用以下方法:
1.) 确定起点和终点之间的直线(直线完全水平或垂直平行于坐标系有两种特殊情况)
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
我必须在服务器上没有安装 EA 的情况下仅使用 .eap 文件绘制一些 EA 图。所以我通过 ODBC 将其作为 MDB 文件打开。
我知道有属性 t_diagramlinks.Geometry
(边={1,2,3,4})和属性 t_connector.Start_Edge
以及属性 t_connector.End_Edge
。
具有属性 Geometry
的 table t_diagramlinks
依赖于图表。
具有属性 .Start_Edge
和 .End_Edge
的 table t_connector
不依赖于图 --> 可能存在未在图上绘制的连接。
我知道t_diagramlinks
的SX、SY、EX、EY是相对于绘制在图上的每个节点的原点的坐标。
问题:EX / EY 有时为零并且没有将结束线绘制到节点的边缘。估计跟鼠标释放位置有关
"My Interpretation" 下面是我的渲染器根据我的假设生成的结果。
"EA Interpretation" 是 EA 实际渲染的内容,我也希望在我的渲染器中看到它。
问题
我在
t_diagramlinks.Geometry
中使用 csv-Value EDGE - 但是在哪里 我要为结束节点找到这个吗?为了什么目的,属性 Start_Edge 和 End_Edge 在 table
t_connector
何时不依赖图表?
I am using in t_diagramlinks.Geometry the csv-Value EDGE - but where do i find this for the end node?
您需要使用 Euclide。 SX,SY/EX,EY 是起始元素和结束元素之间最短中心连接的相对位移。
For which purpose are the attributes Start_Edge an End_Edge in the table "t_connector" when it is not diagram-dependend?
它们用于合格的属性。
编辑:详细说明您的基本问题。 t_diagramlinks.path
保存连接器的弯曲点(如果指定)。因此,为了找到连接器实际连接元素的点,您必须找到离该元素最近的弯曲点。现在在这个弯曲和元素的中间之间你将有一个 natural 附着点。相对于添加 SX-Y (/EX-Y) 以制作手动移动的渲染附着点。
以上内容有保留意见。我从来没有核实过细节,但看到这些数字就用了我的胃。我可能会详细研究以更新我的内幕书,但不能保证。
第二次编辑:现在我知道 "My Interpretation" 是您的渲染器根据您的假设生成的内容,这是(最有可能;见上文)的故事。为了呈现连接器,EA 将使用以下信息:
- 两个连通元素的坐标系
- 根据元素的中点坐标计算
- 连接器的路径属性(如果不为空)
- 离相关元素最近的弯曲点(如果不为空)
- 连接器的偏移因子 SX-Y 和 EX-Y
从起始元素的中点开始,绘制一条虚拟线到最近的弯曲点或结束元素的中间(除非见下文)。这样你就可以在元素的矩形框架上计算虚拟附着点(即使用例有一个矩形框架)。现在你将那个点移动 SX-Y,这将(/应该?)总是沿着元素框架的边缘移动。现在您有了起始元素的虚拟附着点。
在另一边(结束元素;我的 "unless" 从上面)你会做类似的事情来计算结束的虚拟附件。我不知道 EA 这样做的真正顺序(我没有代码洞察力)。因此,如果您在两侧都有手动偏移,则计算将根据将虚拟连接绘制到另一侧的顺序给出不同的结果(因此:是否尊重另一侧的偏移)。基本上我认为你可以忽略 99.9% 的所有情况,其余的只是无关紧要的噪音。
所以现在你知道虚拟端点了,你要么直接连接它们,要么,如果给定路径,你通过弯曲点连接它们。
再说一遍:全都持保留意见。这只是从外面观察,但可能不会太远。还有一个事实是你有不同的线条样式,圆边(这里没有考虑)和贝塞尔线(甚至更多的龙之地)。
非常感谢。我选择用数学方法计算 End-Edge:
我的问题是,我无法在 link 关系上检测到目标端节点的结束边缘。此外还有 8 种不同的 link 类型,它们决定了 link 的布局。因此,正如 Thomas 提到的,我必须检测终点之前的最后一点。如果是路径,则路径的最后一个节点是端点之前的点。如果没有路径,则 startnodes 起点是终点之前的最后一个点。但是,如果定义了路径并且 link 模式已设置为 1,我可能无法处理连接路径,因为 Conn_Path 属性 包含自定义行 - 但在自定义之后用户已选择直接 link(不会被删除)。
后面的数学用的是线性函数y=m*x+b,直线用4条适合端节点边缘的直线描述。
所以你可以做如下算法:
完整的算法使用以下方法:
1.) 确定起点和终点之间的直线(直线完全水平或垂直平行于坐标系有两种特殊情况)
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