Line data Source code
1 1 : export enum EdgeType {
2 : // Angle is multiple of 90
3 1 : West = 0,
4 1 : South = 1,
5 1 : East = 2,
6 1 : North = 3,
7 : // dy >= dx
8 1 : SouthWest = 4,
9 1 : SouthEast = 5,
10 1 : NorthEast = 6,
11 1 : NorthWest = 7,
12 : // dx > dy
13 1 : WestSouth = 8,
14 1 : EastSouth = 9,
15 1 : EastNorth = 10,
16 1 : WestNorth = 11,
17 : // dy >= dx && dx < width
18 1 : SouthWestSouth = 12,
19 1 : SouthEastSouth = 13,
20 1 : NorthEastNorth = 14,
21 1 : NorthWestNorth = 15,
22 : // dx > dy && dy < height
23 1 : WestSouthWest = 16,
24 1 : EastSouthEast = 17,
25 1 : EastNorthEast = 18,
26 1 : WestNorthWest = 19,
27 1 : }
28 :
29 1 : export enum NodePort {
30 1 : North = 0b0001,
31 1 : East = 0b0010,
32 1 : South = 0b0100,
33 1 : West = 0b1000,
34 1 : }
35 :
36 1 : export const PORTS_FROM = new Uint8Array([
37 1 : NodePort.West,
38 1 : NodePort.South,
39 1 : NodePort.East,
40 1 : NodePort.North,
41 1 : NodePort.South,
42 1 : NodePort.South,
43 1 : NodePort.North,
44 1 : NodePort.North,
45 1 : NodePort.West,
46 1 : NodePort.East,
47 1 : NodePort.East,
48 1 : NodePort.West,
49 1 : NodePort.South,
50 1 : NodePort.South,
51 1 : NodePort.North,
52 1 : NodePort.North,
53 1 : NodePort.West,
54 1 : NodePort.East,
55 1 : NodePort.East,
56 1 : NodePort.West,
57 1 : ]);
58 :
59 1 : export const PORTS_TO = new Uint8Array([
60 1 : NodePort.East,
61 1 : NodePort.North,
62 1 : NodePort.West,
63 1 : NodePort.South,
64 1 : NodePort.East,
65 1 : NodePort.West,
66 1 : NodePort.West,
67 1 : NodePort.East,
68 1 : NodePort.North,
69 1 : NodePort.North,
70 1 : NodePort.South,
71 1 : NodePort.South,
72 1 : NodePort.North,
73 1 : NodePort.North,
74 1 : NodePort.South,
75 1 : NodePort.South,
76 1 : NodePort.East,
77 1 : NodePort.West,
78 1 : NodePort.West,
79 1 : NodePort.East,
80 1 : ]);
81 :
82 : /// Atan2 circle https://commons.wikimedia.org/wiki/File:Atan2_circle.svg
83 1 : export function selectEdgeTypeFromAngle(angle: number): EdgeType {
84 : // atan2 returns 180 for a target straight west, which is the sector -2 (West) as well
85 1 : const sector = angle === 180 ? -2 : angle / 90; // [-2, 2[
86 1 : if (sector == Math.floor(sector)) {
87 : // One of [-2, -1, 0, 1, 2]
88 : //
89 : // Becomes:
90 : // West = 0,
91 : // South = 1,
92 : // East = 2,
93 : // North = 3,
94 1 : return (sector + 2) as EdgeType; // [0, 4[
95 : } else {
96 : // We round the value, use the subsequent sector
97 : //
98 : // Becomes:
99 : // SouthWest = 4,
100 : // SouthEast = 5,
101 : // NorthEast = 6,
102 : // NorthWest = 7,
103 1 : return (Math.floor(sector) + 2 + 4) as EdgeType; // [4, 8[
104 : }
105 1 : }
106 :
107 : /// Select edge type using node dimensions
108 1 : export function selectEdgeType(
109 1 : fromX: number,
110 1 : fromY: number,
111 1 : toX: number,
112 1 : toY: number,
113 1 : width: number,
114 1 : height: number,
115 1 : ): EdgeType {
116 1 : const dx = toX - fromX;
117 1 : const dy = toY - fromY;
118 1 : const angle = (Math.atan2(dy, dx) * 180) / Math.PI;
119 1 : let orientation = selectEdgeTypeFromAngle(angle);
120 : // const boxWidth = (widthX + widthY) / 2;
121 : // const boxHeight = (heightX + heightY) / 2;
122 1 : const boxDx = Math.max(Math.abs(dx), width) - width;
123 1 : const boxDy = Math.max(Math.abs(dy), height) - height;
124 1 : if (orientation >= 4) {
125 : // Is the horizontal distance larger than vertical?
126 : // Horizontal -> East/West first
127 : // Vertical -> North/South first
128 1 : if (boxDx > boxDy) {
129 1 : orientation += 4; // [8, 12[
130 :
131 : // If dy < boxHeight, we cannot render like:
132 : // |
133 : // +--
134 : // but have to render like:
135 : // --+
136 : // |
137 : // +--
138 : //
139 1 : if (Math.abs(dy) < height) {
140 1 : orientation += 8; // [16, 20[
141 : }
142 1 : } else {
143 : // If dx < boxWidth, we cannot render like:
144 : // --+
145 : // |
146 : // but have to render like:
147 : // |
148 : // +-+
149 : // |
150 : //
151 1 : if (Math.abs(dx) < width) {
152 1 : orientation += 8; // [12, 16[
153 : }
154 : }
155 1 : }
156 1 : return orientation;
157 1 : }
158 :
159 : /// Select horizontal edge type using node dimensions
160 1 : export function selectHorizontalEdgeType(
161 1 : fromX: number,
162 1 : fromY: number,
163 1 : toX: number,
164 1 : toY: number,
165 1 : ): EdgeType {
166 1 : const dx = toX - fromX;
167 1 : const dy = toY - fromY;
168 1 : const angle = (Math.atan2(dy, dx) * 180) / Math.PI;
169 1 : let orientation = selectEdgeTypeFromAngle(angle);
170 1 : if (orientation >= 4) {
171 1 : return orientation + 12; // [16, 20[
172 : } else {
173 1 : return orientation;
174 : }
175 1 : }
176 :
177 : /// Select vertical edge type using node dimensions
178 1 : export function selectVerticalEdgeType(
179 1 : fromX: number,
180 1 : fromY: number,
181 1 : toX: number,
182 1 : toY: number,
183 1 : ): EdgeType {
184 1 : const dx = toX - fromX;
185 1 : const dy = toY - fromY;
186 1 : const angle = (Math.atan2(dy, dx) * 180) / Math.PI;
187 1 : let orientation = selectEdgeTypeFromAngle(angle);
188 1 : if (orientation >= 4) {
189 1 : return orientation + 8; // [12, 16[
190 : } else {
191 1 : return orientation;
192 : }
193 1 : }
194 :
195 1 : export enum PathType {
196 1 : NONE,
197 1 : DIRECT,
198 1 : SINGLE_TURN,
199 1 : TWO_TURNS,
200 1 : }
201 :
202 1 : export class PathBuilder {
203 : /// The path type
204 1 : pathType: PathType;
205 : /// The path buffer
206 1 : path: Float64Array;
207 : /// The current size
208 1 : i: number;
209 :
210 1 : constructor() {
211 1 : this.pathType = PathType.NONE;
212 1 : this.path = new Float64Array(16);
213 1 : this.i = 0;
214 1 : }
215 1 : clear() {
216 1 : for (let i = 0; i < 16; ++i) {
217 1 : this.path[i] = 0;
218 : }
219 1 : this.i = 0;
220 1 : }
221 0 : last(): [number, number] {
222 0 : return (this.i < 2) ? [0, 0] : [this.path[this.i - 2], this.path[this.i - 1]];
223 0 : }
224 1 : begin(x: number, y: number) {
225 1 : this.clear();
226 1 : this.path[0] = x;
227 1 : this.path[1] = y;
228 1 : }
229 1 : push(x: number, y: number) {
230 1 : this.i += 2;
231 1 : this.path[this.i] = x;
232 1 : this.path[this.i + 1] = y;
233 1 : }
234 1 : finish(pathType: PathType): PathBuilder {
235 1 : this.pathType = pathType;
236 1 : return this;
237 1 : }
238 1 : render(standalone: boolean = true): string {
239 1 : const p = this.path;
240 1 : const prefix = standalone ? 'M' : 'L';
241 1 : switch (this.pathType) {
242 1 : case PathType.NONE:
243 1 : return "";
244 1 : case PathType.DIRECT:
245 1 : return `${prefix} ${p[0]} ${p[1]} L ${p[2]} ${p[3]}`;
246 1 : case PathType.SINGLE_TURN:
247 1 : return `${prefix} ${p[0]} ${p[1]} L ${p[2]} ${p[3]} Q ${p[4]} ${p[5]}, ${p[6]} ${p[7]} L ${p[8]} ${p[9]}`;
248 1 : case PathType.TWO_TURNS:
249 1 : return `${prefix} ${p[0]} ${p[1]} L ${p[2]} ${p[3]} Q ${p[4]} ${p[5]}, ${p[6]} ${p[7]} L ${p[8]} ${p[9]} Q ${p[10]} ${p[11]}, ${p[12]} ${p[13]} L ${p[14]} ${p[15]}`;
250 1 : }
251 1 : }
252 1 : }
253 :
254 1 : export function buildEdgePathBetweenRectangles(
255 1 : builder: PathBuilder,
256 1 : type: EdgeType,
257 1 : fromCenterX: number,
258 1 : fromCenterY: number,
259 1 : toCenterX: number,
260 1 : toCenterY: number,
261 1 : fromWidth: number,
262 1 : fromHeight: number,
263 1 : toWidth: number,
264 1 : toHeight: number,
265 1 : cornerRadius: number,
266 1 : offset: number = 0,
267 1 : ): PathBuilder {
268 1 : if (toCenterX - fromCenterX == 0 && toCenterY - fromCenterY == 0) {
269 1 : return builder;
270 : }
271 1 : const r = cornerRadius;
272 :
273 : // Note that North/South/East/West is a bit confusing here in the context of SVG:
274 : // - We use North as North relative to the target coordinate system.
275 : // - That means North == Larger Y, South == Smaller Y
276 : // - This breaks intuition in SVG since there (0, 0) is in the top-left!
277 : // - In SVG, don't assume that NORTH means an edge is going upwards!
278 :
279 : // The offset is applied in counter clockwise direction.
280 :
281 1 : switch (type) {
282 : // DIRECT
283 :
284 : // B
285 : // |
286 : // A
287 1 : case EdgeType.North:
288 1 : fromCenterX += offset;
289 1 : toCenterX += offset;
290 1 : builder.begin(fromCenterX, fromCenterY + fromHeight / 2);
291 1 : builder.push(toCenterX, toCenterY - toHeight / 2);
292 1 : return builder.finish(PathType.DIRECT);
293 :
294 : // A
295 : // |
296 : // B
297 1 : case EdgeType.South:
298 1 : fromCenterX -= offset;
299 1 : toCenterX -= offset;
300 1 : builder.begin(fromCenterX, fromCenterY - fromHeight / 2);
301 1 : builder.push(toCenterX, toCenterY + toHeight / 2);
302 1 : return builder.finish(PathType.DIRECT);
303 :
304 : // A-B
305 1 : case EdgeType.East:
306 1 : fromCenterY -= offset;
307 1 : toCenterY -= offset;
308 1 : builder.begin(fromCenterX + fromWidth / 2, fromCenterY);
309 1 : builder.push(toCenterX - toWidth / 2, toCenterY);
310 1 : return builder.finish(PathType.DIRECT);
311 :
312 : // B-A
313 1 : case EdgeType.West:
314 1 : fromCenterY += offset;
315 1 : toCenterY += offset;
316 1 : builder.begin(fromCenterX - fromWidth / 2, fromCenterY);
317 1 : builder.push(toCenterX + toWidth / 2, toCenterY);
318 1 : return builder.finish(PathType.DIRECT);
319 :
320 : // 1 TURN
321 :
322 : // +-B
323 : // |
324 : // A
325 1 : case EdgeType.NorthEast: {
326 1 : fromCenterY += fromHeight / 2;
327 1 : toCenterX -= toWidth / 2;
328 1 : const diffX = Math.abs(toCenterX - fromCenterX);
329 1 : const diffY = Math.abs(toCenterY - fromCenterY);
330 1 : fromCenterX += offset;
331 1 : toCenterY -= offset;
332 1 : builder.begin(fromCenterX, fromCenterY);
333 1 : builder.push(fromCenterX, toCenterY - Math.min(diffY / 2, r) - r);
334 1 : builder.push(fromCenterX, toCenterY);
335 1 : builder.push(fromCenterX + Math.min(diffX / 2, r), toCenterY);
336 1 : builder.push(toCenterX, toCenterY);
337 1 : return builder.finish(PathType.SINGLE_TURN);
338 1 : }
339 :
340 : // B-+
341 : // |
342 : // A
343 1 : case EdgeType.NorthWest: {
344 1 : fromCenterY += fromHeight / 2;
345 1 : toCenterX += toWidth / 2;
346 1 : const diffX = Math.abs(toCenterX - fromCenterX);
347 1 : const diffY = Math.abs(toCenterY - fromCenterY);
348 1 : fromCenterX += offset;
349 1 : toCenterY += offset;
350 1 : builder.begin(fromCenterX, fromCenterY);
351 1 : builder.push(fromCenterX, toCenterY - Math.min(diffY / 2, r));
352 1 : builder.push(fromCenterX, toCenterY);
353 1 : builder.push(fromCenterX - Math.min(diffX / 2, r), toCenterY);
354 1 : builder.push(toCenterX, toCenterY);
355 1 : return builder.finish(PathType.SINGLE_TURN);
356 1 : }
357 :
358 : // A
359 : // |
360 : // +-B
361 1 : case EdgeType.SouthEast: {
362 1 : fromCenterY -= fromHeight / 2;
363 1 : toCenterX -= toWidth / 2;
364 1 : const diffX = Math.abs(toCenterX - fromCenterX);
365 1 : const diffY = Math.abs(toCenterY - fromCenterY);
366 1 : fromCenterX -= offset;
367 1 : toCenterY -= offset;
368 1 : builder.begin(fromCenterX, fromCenterY);
369 1 : builder.push(fromCenterX, toCenterY + Math.min(diffY / 2, r));
370 1 : builder.push(fromCenterX, toCenterY);
371 1 : builder.push(fromCenterX + Math.min(diffX / 2, r), toCenterY);
372 1 : builder.push(toCenterX, toCenterY);
373 1 : return builder.finish(PathType.SINGLE_TURN);
374 1 : }
375 :
376 : // A
377 : // |
378 : // B-+
379 1 : case EdgeType.SouthWest: {
380 1 : fromCenterY -= fromHeight / 2;
381 1 : toCenterX += toWidth / 2;
382 1 : const diffX = Math.abs(toCenterX - fromCenterX);
383 1 : const diffY = Math.abs(toCenterY - fromCenterY);
384 1 : fromCenterX -= offset;
385 1 : toCenterY += offset;
386 1 : builder.begin(fromCenterX, fromCenterY);
387 1 : builder.push(fromCenterX, toCenterY + Math.min(diffY / 2, r));
388 1 : builder.push(fromCenterX, toCenterY);
389 1 : builder.push(fromCenterX - Math.min(diffX / 2, r), toCenterY);
390 1 : builder.push(toCenterX, toCenterY);
391 1 : return builder.finish(PathType.SINGLE_TURN);
392 1 : }
393 :
394 : // B
395 : // |
396 : // A-+
397 1 : case EdgeType.EastNorth: {
398 1 : fromCenterX += fromWidth / 2;
399 1 : toCenterY -= toHeight / 2;
400 1 : const diffX = Math.abs(toCenterX - fromCenterX);
401 1 : const diffY = Math.abs(toCenterY - fromCenterY);
402 1 : fromCenterY -= offset;
403 1 : toCenterX += offset;
404 1 : builder.begin(fromCenterX, fromCenterY);
405 1 : builder.push(toCenterX - Math.min(diffX / 2, r), fromCenterY);
406 1 : builder.push(toCenterX, fromCenterY);
407 1 : builder.push(toCenterX, fromCenterY + Math.min(diffY / 2, r));
408 1 : builder.push(toCenterX, toCenterY);
409 1 : return builder.finish(PathType.SINGLE_TURN);
410 1 : }
411 :
412 : // A-+
413 : // |
414 : // B
415 1 : case EdgeType.EastSouth: {
416 1 : fromCenterX += fromWidth / 2;
417 1 : toCenterY += toHeight / 2;
418 1 : const diffX = Math.abs(toCenterX - fromCenterX);
419 1 : const diffY = Math.abs(toCenterY - fromCenterY);
420 1 : fromCenterY -= offset;
421 1 : toCenterX -= offset;
422 1 : builder.begin(fromCenterX, fromCenterY);
423 1 : builder.push(toCenterX - Math.min(diffX / 2, r), fromCenterY);
424 1 : builder.push(toCenterX, fromCenterY);
425 1 : builder.push(toCenterX, fromCenterY - Math.min(diffY / 2, r));
426 1 : builder.push(toCenterX, toCenterY);
427 1 : return builder.finish(PathType.SINGLE_TURN);
428 1 : }
429 :
430 : // B
431 : // |
432 : // +-A
433 1 : case EdgeType.WestNorth: {
434 1 : fromCenterX -= fromWidth / 2;
435 1 : toCenterY -= toHeight / 2;
436 1 : const diffX = Math.abs(toCenterX - fromCenterX);
437 1 : const diffY = Math.abs(toCenterY - fromCenterY);
438 1 : fromCenterY += offset;
439 1 : toCenterX += offset;
440 1 : builder.begin(fromCenterX, fromCenterY);
441 1 : builder.push(toCenterX + Math.min(diffX / 2, r), fromCenterY);
442 1 : builder.push(toCenterX, fromCenterY);
443 1 : builder.push(toCenterX, fromCenterY + Math.min(diffY / 2, r));
444 1 : builder.push(toCenterX, toCenterY);
445 1 : return builder.finish(PathType.SINGLE_TURN);
446 1 : }
447 :
448 : // +-A
449 : // |
450 : // B
451 1 : case EdgeType.WestSouth: {
452 1 : fromCenterX -= fromWidth / 2;
453 1 : toCenterY += toHeight / 2;
454 1 : const diffX = Math.abs(toCenterX - fromCenterX);
455 1 : const diffY = Math.abs(toCenterY - fromCenterY);
456 1 : fromCenterY -= offset;
457 1 : toCenterX += offset;
458 1 : builder.begin(fromCenterX, fromCenterY);
459 1 : builder.push(toCenterX + Math.min(diffX / 2, r), fromCenterY);
460 1 : builder.push(toCenterX, fromCenterY);
461 1 : builder.push(toCenterX, fromCenterY - Math.min(diffY / 2, r));
462 1 : builder.push(toCenterX, toCenterY);
463 1 : return builder.finish(PathType.SINGLE_TURN);
464 1 : }
465 :
466 : // 2 TURNS
467 :
468 : // +-B
469 : // |
470 : // A-+
471 1 : case EdgeType.EastNorthEast: {
472 1 : fromCenterX += fromWidth / 2;
473 1 : toCenterX -= toWidth / 2;
474 1 : const diffX = Math.abs(toCenterX - fromCenterX);
475 1 : const diffY = Math.abs(toCenterY - fromCenterY);
476 1 : let midX = fromCenterX + diffX / 2;
477 1 : fromCenterY -= offset;
478 1 : toCenterY -= offset;
479 1 : midX += offset;
480 1 : builder.begin(fromCenterX, fromCenterY);
481 1 : builder.push(midX - Math.min(diffX / 2, r), fromCenterY);
482 1 : builder.push(midX, fromCenterY);
483 1 : builder.push(midX, fromCenterY + Math.min(diffY / 2, r));
484 1 : builder.push(midX, toCenterY - Math.min(diffY / 2, r));
485 1 : builder.push(midX, toCenterY);
486 1 : builder.push(midX + Math.min(diffX / 2, r), toCenterY);
487 1 : builder.push(toCenterX, toCenterY);
488 1 : return builder.finish(PathType.TWO_TURNS);
489 1 : }
490 :
491 : // A-+
492 : // |
493 : // +-B
494 1 : case EdgeType.EastSouthEast: {
495 1 : fromCenterX += fromWidth / 2;
496 1 : toCenterX -= toWidth / 2;
497 1 : const diffX = Math.abs(toCenterX - fromCenterX);
498 1 : const diffY = Math.abs(toCenterY - fromCenterY);
499 1 : let midX = fromCenterX + diffX / 2;
500 1 : fromCenterY -= offset;
501 1 : toCenterY -= offset;
502 1 : midX -= offset;
503 1 : builder.begin(fromCenterX, fromCenterY);
504 1 : builder.push(midX - Math.min(diffX / 2, r), fromCenterY);
505 1 : builder.push(midX, fromCenterY);
506 1 : builder.push(midX, fromCenterY - Math.min(diffY / 2, r));
507 1 : builder.push(midX, toCenterY + Math.min(diffY / 2, r));
508 1 : builder.push(midX, toCenterY);
509 1 : builder.push(midX + Math.min(diffX / 2, r), toCenterY);
510 1 : builder.push(toCenterX, toCenterY);
511 1 : return builder.finish(PathType.TWO_TURNS);
512 1 : }
513 :
514 : // A
515 : // |
516 : // +-+
517 : // |
518 : // B
519 1 : case EdgeType.SouthEastSouth: {
520 1 : fromCenterY -= fromHeight / 2;
521 1 : toCenterY += toHeight / 2;
522 1 : const diffX = Math.abs(toCenterX - fromCenterX);
523 1 : const diffY = Math.abs(toCenterY - fromCenterY);
524 1 : let midY = fromCenterY - diffY / 2;
525 1 : fromCenterX -= offset;
526 1 : toCenterX -= offset;
527 1 : midY -= offset;
528 1 : builder.begin(fromCenterX, fromCenterY);
529 1 : builder.push(fromCenterX, midY + Math.min(diffY / 2, r));
530 1 : builder.push(fromCenterX, midY);
531 1 : builder.push(fromCenterX + Math.min(diffX / 2, r), midY);
532 1 : builder.push(toCenterX - Math.min(diffX / 2, r), midY);
533 1 : builder.push(toCenterX, midY);
534 1 : builder.push(toCenterX, midY - Math.min(diffY / 2, r));
535 1 : builder.push(toCenterX, toCenterY);
536 1 : return builder.finish(PathType.TWO_TURNS);
537 1 : }
538 :
539 : // A
540 : // |
541 : // +-+
542 : // |
543 : // B
544 1 : case EdgeType.SouthWestSouth: {
545 1 : fromCenterY -= fromHeight / 2;
546 1 : toCenterY += toHeight / 2;
547 1 : const diffX = Math.abs(toCenterX - fromCenterX);
548 1 : const diffY = Math.abs(toCenterY - fromCenterY);
549 1 : let midY = fromCenterY - diffY / 2;
550 1 : fromCenterX -= offset;
551 1 : toCenterX -= offset
552 1 : midY += offset;
553 1 : builder.begin(fromCenterX, fromCenterY);
554 1 : builder.push(fromCenterX, midY + Math.min(diffY / 2, r));
555 1 : builder.push(fromCenterX, midY);
556 1 : builder.push(fromCenterX - Math.min(diffX / 2, r), midY);
557 1 : builder.push(toCenterX + Math.min(diffX / 2, r), midY);
558 1 : builder.push(toCenterX, midY);
559 1 : builder.push(toCenterX, midY - Math.min(diffY / 2, r));
560 1 : builder.push(toCenterX, toCenterY);
561 1 : return builder.finish(PathType.TWO_TURNS);
562 1 : }
563 :
564 : // B-+
565 : // |
566 : // +-A
567 1 : case EdgeType.WestNorthWest: {
568 1 : fromCenterX -= fromWidth / 2;
569 1 : toCenterX += toWidth / 2;
570 1 : const diffX = Math.abs(toCenterX - fromCenterX);
571 1 : const diffY = Math.abs(toCenterY - fromCenterY);
572 1 : let midX = fromCenterX - diffX / 2;
573 1 : fromCenterY += offset;
574 1 : toCenterY += offset;
575 1 : midX += offset;
576 1 : builder.begin(fromCenterX, fromCenterY);
577 1 : builder.push(midX + Math.min(diffX / 2, r), fromCenterY);
578 1 : builder.push(midX, fromCenterY);
579 1 : builder.push(midX, fromCenterY + Math.min(diffY / 2, r));
580 1 : builder.push(midX, toCenterY - Math.min(diffY / 2, r));
581 1 : builder.push(midX, toCenterY);
582 1 : builder.push(midX - Math.min(diffX / 2, r), toCenterY);
583 1 : builder.push(toCenterX, toCenterY);
584 1 : return builder.finish(PathType.TWO_TURNS);
585 1 : }
586 :
587 : // +-A
588 : // |
589 : // B-+
590 1 : case EdgeType.WestSouthWest: {
591 1 : fromCenterX -= fromWidth / 2;
592 1 : toCenterX += toWidth / 2;
593 1 : const diffX = Math.abs(toCenterX - fromCenterX);
594 1 : const diffY = Math.abs(toCenterY - fromCenterY);
595 1 : let midX = fromCenterX - diffX / 2;
596 1 : fromCenterY += offset;
597 1 : toCenterY += offset;
598 1 : midX -= offset;
599 1 : builder.begin(fromCenterX, fromCenterY);
600 1 : builder.push(midX + Math.min(diffX / 2, r), fromCenterY);
601 1 : builder.push(midX, fromCenterY);
602 1 : builder.push(midX, fromCenterY - Math.min(diffY / 2, r));
603 1 : builder.push(midX, toCenterY + Math.min(diffY / 2, r));
604 1 : builder.push(midX, toCenterY);
605 1 : builder.push(midX - Math.min(diffX / 2, r), toCenterY);
606 1 : builder.push(toCenterX, toCenterY);
607 1 : return builder.finish(PathType.TWO_TURNS);
608 1 : }
609 :
610 : // B
611 : // |
612 : // +-+
613 : // |
614 : // A
615 1 : case EdgeType.NorthEastNorth: {
616 1 : fromCenterY += fromHeight / 2;
617 1 : toCenterY -= toHeight / 2;
618 1 : const diffX = Math.abs(toCenterX - fromCenterX);
619 1 : const diffY = Math.abs(toCenterY - fromCenterY);
620 1 : let midY = fromCenterY + diffY / 2;
621 1 : fromCenterX += offset;
622 1 : toCenterX += offset;
623 1 : midY -= offset;
624 1 : builder.begin(fromCenterX, fromCenterY);
625 1 : builder.push(fromCenterX, midY - Math.min(diffY / 2, r));
626 1 : builder.push(fromCenterX, midY);
627 1 : builder.push(fromCenterX + Math.min(diffX / 2, r), midY);
628 1 : builder.push(toCenterX - Math.min(diffX / 2, r), midY);
629 1 : builder.push(toCenterX, midY);
630 1 : builder.push(toCenterX, midY + Math.min(diffY / 2, r));
631 1 : builder.push(toCenterX, toCenterY);
632 1 : return builder.finish(PathType.TWO_TURNS);
633 1 : }
634 :
635 : // B
636 : // |
637 : // +-+
638 : // |
639 : // A
640 1 : case EdgeType.NorthWestNorth: {
641 1 : fromCenterY += fromHeight / 2;
642 1 : toCenterY -= toHeight / 2;
643 1 : const diffX = Math.abs(toCenterX - fromCenterX);
644 1 : const diffY = Math.abs(toCenterY - fromCenterY);
645 1 : let midY = fromCenterY + diffY / 2;
646 1 : fromCenterX += offset;
647 1 : toCenterX += offset;
648 1 : midY += offset;
649 1 : builder.begin(fromCenterX, fromCenterY);
650 1 : builder.push(fromCenterX, midY - Math.min(diffY / 2, r));
651 1 : builder.push(fromCenterX, midY);
652 1 : builder.push(fromCenterX - Math.min(diffX / 2, r), midY);
653 1 : builder.push(toCenterX + Math.min(diffX / 2, r), midY);
654 1 : builder.push(toCenterX, midY);
655 1 : builder.push(toCenterX, midY + Math.min(diffY / 2, r));
656 1 : builder.push(toCenterX, toCenterY);
657 1 : return builder.finish(PathType.TWO_TURNS);
658 1 : }
659 1 : }
660 1 : }
|