@@ -42,7 +42,9 @@ export class PolylineEdgeModel extends BaseEdgeModel {
4242 ? providedOffset
4343 : this . getDefaultOffset ( )
4444 if ( data . pointsList ) {
45- this . pointsList = data . pointsList
45+ const corrected = this . orthogonalizePath ( data . pointsList )
46+ ; ( data as any ) . pointsList = corrected
47+ this . pointsList = corrected
4648 }
4749 super . initEdgeData ( data )
4850 }
@@ -55,6 +57,120 @@ export class PolylineEdgeModel extends BaseEdgeModel {
5557 }
5658 }
5759
60+ orthogonalizePath ( points : Point [ ] ) : Point [ ] {
61+ // 输入非法或不足两点时直接返回副本
62+ if ( ! Array . isArray ( points ) || points . length < 2 ) {
63+ return points
64+ }
65+ // pushUnique: 向数组中添加唯一点,避免重复
66+ const pushUnique = ( arr : Point [ ] , p : Point ) => {
67+ const last = arr [ arr . length - 1 ]
68+ if ( ! last || last . x !== p . x || last . y !== p . y ) {
69+ arr . push ( { x : p . x , y : p . y } )
70+ }
71+ }
72+ // isAxisAligned: 检查两点是否在同一条轴上
73+ const isAxisAligned = ( a : Point , b : Point ) => a . x === b . x || a . y === b . y
74+ // manhattanDistance: 计算两点在曼哈顿距离上的距离
75+ const manhattanDistance = ( a : Point , b : Point ) =>
76+ Math . abs ( a . x - b . x ) + Math . abs ( a . y - b . y )
77+
78+ // 1) 生成严格正交路径,尽量延续前一段方向以减少折点
79+ const orthogonal : Point [ ] = [ ]
80+ pushUnique ( orthogonal , points [ 0 ] )
81+ // previousDirection: 记录前一段的方向,用于判断当前段的PreferredCorner
82+ let previousDirection : SegmentDirection | undefined
83+ // 遍历所有点对,生成正交路径
84+ for ( let i = 0 ; i < points . length - 1 ; i ++ ) {
85+ const current = orthogonal [ orthogonal . length - 1 ]
86+ const next = points [ i + 1 ]
87+ if ( ! current || ! next ) continue
88+
89+ if ( isAxisAligned ( current , next ) ) {
90+ pushUnique ( orthogonal , next )
91+ previousDirection =
92+ current . x === next . x
93+ ? SegmentDirection . VERTICAL
94+ : SegmentDirection . HORIZONTAL
95+ continue
96+ }
97+
98+ const cornerHV : Point = { x : next . x , y : current . y }
99+ const cornerVH : Point = { x : current . x , y : next . y }
100+
101+ // 根据前一段的方向,优先选择能延续该方向的拐角点,以减少折点数量;
102+ // 若前一段为垂直方向,则优先选择垂直-水平拐角(cornerVH);
103+ // 若前一段为水平方向,则优先选择水平-垂直拐角(cornerHV);
104+ // 若前一段无方向(初始情况),则比较两个拐角的曼哈顿距离,选更近者。
105+ const preferredCorner =
106+ previousDirection === SegmentDirection . VERTICAL
107+ ? cornerVH
108+ : previousDirection === SegmentDirection . HORIZONTAL
109+ ? cornerHV
110+ : manhattanDistance ( current , cornerHV ) <=
111+ manhattanDistance ( current , cornerVH )
112+ ? cornerHV
113+ : cornerVH
114+
115+ if ( preferredCorner . x !== current . x || preferredCorner . y !== current . y ) {
116+ pushUnique ( orthogonal , preferredCorner )
117+ }
118+ pushUnique ( orthogonal , next )
119+
120+ const a = orthogonal [ orthogonal . length - 2 ]
121+ const b = orthogonal [ orthogonal . length - 1 ]
122+ previousDirection =
123+ a && b
124+ ? a . x === b . x
125+ ? SegmentDirection . VERTICAL
126+ : SegmentDirection . HORIZONTAL
127+ : previousDirection
128+ }
129+
130+ // 2) 去除冗余共线中间点
131+ const simplified : Point [ ] = [ ]
132+ for ( let i = 0 ; i < orthogonal . length ; i ++ ) {
133+ const prev = orthogonal [ i - 1 ]
134+ const curr = orthogonal [ i ]
135+ const next = orthogonal [ i + 1 ]
136+ // 如果当前点与前一个点和后一个点在同一条水平线或垂直线上,则跳过该点,去除冗余的共线中间点
137+ if (
138+ prev &&
139+ curr &&
140+ next &&
141+ ( ( prev . x === curr . x && curr . x === next . x ) || // 水平共线
142+ ( prev . y === curr . y && curr . y === next . y ) ) // 垂直共线
143+ ) {
144+ continue
145+ }
146+ pushUnique ( simplified , curr )
147+ }
148+
149+ // 3) 保留原始起点与终点位置
150+ if ( simplified . length >= 2 ) {
151+ simplified [ 0 ] = { x : points [ 0 ] . x , y : points [ 0 ] . y }
152+ simplified [ simplified . length - 1 ] = {
153+ x : points [ points . length - 1 ] . x ,
154+ y : points [ points . length - 1 ] . y ,
155+ }
156+ }
157+
158+ // 4) 结果校验:任意相邻段都必须为水平/垂直;失败则退化为起止两点
159+ const isOrthogonal =
160+ simplified . length < 2 ||
161+ simplified . every ( ( _ , idx , arr ) => {
162+ if ( idx === 0 ) return true
163+ return isAxisAligned ( arr [ idx - 1 ] , arr [ idx ] )
164+ } )
165+
166+ return isOrthogonal
167+ ? simplified
168+ : [
169+ { x : points [ 0 ] . x , y : points [ 0 ] . y } ,
170+ { x : points [ points . length - 1 ] . x , y : points [ points . length - 1 ] . y } ,
171+ ]
172+ }
173+
58174 /**
59175 * 计算默认 offset:箭头与折线重叠长度 + 5
60176 * 重叠长度采用箭头样式中的 offset(沿边方向的长度)
@@ -344,7 +460,7 @@ export class PolylineEdgeModel extends BaseEdgeModel {
344460 }
345461
346462 updatePath ( pointList : Point [ ] ) {
347- this . pointsList = pointList
463+ this . pointsList = this . orthogonalizePath ( pointList )
348464 this . points = this . getPath ( this . pointsList )
349465 }
350466
@@ -387,7 +503,7 @@ export class PolylineEdgeModel extends BaseEdgeModel {
387503 this . targetNode ,
388504 this . offset || 0 ,
389505 )
390- this . pointsList = pointsList
506+ this . pointsList = this . orthogonalizePath ( pointsList )
391507 this . points = pointsList . map ( ( point ) => `${ point . x } ,${ point . y } ` ) . join ( ' ' )
392508 }
393509
@@ -676,18 +792,20 @@ export class PolylineEdgeModel extends BaseEdgeModel {
676792 sourceNode : BaseNodeModel
677793 targetNode : BaseNodeModel
678794 } ) {
679- this . pointsList = getPolylinePoints (
680- {
681- x : startPoint . x ,
682- y : startPoint . y ,
683- } ,
684- {
685- x : endPoint . x ,
686- y : endPoint . y ,
687- } ,
688- sourceNode ,
689- targetNode ,
690- this . offset || 0 ,
795+ this . pointsList = this . orthogonalizePath (
796+ getPolylinePoints (
797+ {
798+ x : startPoint . x ,
799+ y : startPoint . y ,
800+ } ,
801+ {
802+ x : endPoint . x ,
803+ y : endPoint . y ,
804+ } ,
805+ sourceNode ,
806+ targetNode ,
807+ this . offset || 0 ,
808+ ) ,
691809 )
692810
693811 this . initPoints ( )
0 commit comments