@leafer-in/linker 2.3.3 → 2.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/linker.cjs CHANGED
@@ -226,7 +226,7 @@ function getPolylineDirectionIndex(direction) {
226
226
  }
227
227
  }
228
228
 
229
- function getPolylinePorts(direction, point, target, bounds, targetBounds, ports) {
229
+ function getPolylinePorts(direction, point, target, bounds, targetBounds) {
230
230
  const data = directionData[getPolylineDirectionIndex(direction)];
231
231
  const dx = Math.sign(data.x - .5), dy = Math.sign(data.y - .5);
232
232
  const cx = bounds ? bounds.x + bounds.width / 2 : point.x;
@@ -234,39 +234,27 @@ function getPolylinePorts(direction, point, target, bounds, targetBounds, ports)
234
234
  const tx = targetBounds ? targetBounds.x + targetBounds.width / 2 : target.x;
235
235
  const ty = targetBounds ? targetBounds.y + targetBounds.height / 2 : target.y;
236
236
  const deltaX = tx - cx, deltaY = ty - cy;
237
- const xSign = dx || (deltaX >= 0 ? 1 : -1);
238
- const ySign = dy || (deltaY >= 0 ? 1 : -1);
239
- const xPort = POLYLINE_X * 2 + (xSign > 0 ? 1 : 0);
240
- const yPort = POLYLINE_Y * 2 + (ySign > 0 ? 1 : 0);
241
- if (dx && !dy) {
242
- ports[0] = xPort;
243
- return 1;
244
- }
245
- if (dy && !dx) {
246
- ports[0] = yPort;
247
- return 1;
248
- }
249
- if (Math.abs(deltaX) >= Math.abs(deltaY)) {
250
- ports[0] = xPort;
251
- ports[1] = yPort;
252
- } else {
253
- ports[0] = yPort;
254
- ports[1] = xPort;
255
- }
256
- return 2;
237
+ const xPort = (dx || (deltaX >= 0 ? 1 : -1)) > 0 ? 1 : 0;
238
+ const yPort = (dy || (deltaY >= 0 ? 1 : -1)) > 0 ? 3 : 2;
239
+ if (dx && !dy) return [ xPort ];
240
+ if (dy && !dx) return [ yPort ];
241
+ return Math.abs(deltaX) >= Math.abs(deltaY) ? [ xPort, yPort ] : [ yPort, xPort ];
257
242
  }
258
243
 
259
- function getPolylineExit(point, bounds, port, clearance, result) {
244
+ function getPolylineExit(point, bounds, port, clearance) {
260
245
  const axis = port >> 1, sign = port & 1 ? 1 : -1;
261
246
  if (axis === POLYLINE_X) {
262
- const boundary = bounds ? sign > 0 ? bounds.x + bounds.width : bounds.x : point.x;
263
- result[0] = boundary + sign * clearance;
264
- result[1] = point.y;
265
- } else {
266
- const boundary = bounds ? sign > 0 ? bounds.y + bounds.height : bounds.y : point.y;
267
- result[0] = point.x;
268
- result[1] = boundary + sign * clearance;
269
- }
247
+ const x = bounds ? bounds.x + (sign > 0 ? bounds.width : 0) : point.x;
248
+ return {
249
+ x: x + sign * clearance,
250
+ y: point.y
251
+ };
252
+ }
253
+ const y = bounds ? bounds.y + (sign > 0 ? bounds.height : 0) : point.y;
254
+ return {
255
+ x: point.x,
256
+ y: y + sign * clearance
257
+ };
270
258
  }
271
259
 
272
260
  function isPolylinePointBlocked(x, y, bounds, clearance) {
@@ -320,45 +308,69 @@ function getPolylineMidpointAxis(startPort, endPort, sx, sy, ex, ey) {
320
308
  return Math.abs(ex - sx) >= Math.abs(ey - sy) ? POLYLINE_X : POLYLINE_Y;
321
309
  }
322
310
 
323
- function getPolylineMidpointRoute(result, startPoint, endPoint, sx, sy, ex, ey, midpointAxis, startBounds, endBounds, clearance) {
324
- const midpointX = (sx + ex) / 2, midpointY = (sy + ey) / 2;
325
- result.length = 0;
326
- result.push(startPoint.x, startPoint.y, sx, sy);
327
- if (midpointAxis === POLYLINE_X) {
328
- result.push(midpointX, sy, midpointX, ey);
329
- } else {
330
- result.push(sx, midpointY, ex, midpointY);
331
- }
332
- result.push(ex, ey, endPoint.x, endPoint.y);
333
- for (let i = 4; i < result.length - 2; i += 2) {
334
- const x1 = result[i - 2], y1 = result[i - 1];
335
- const x2 = result[i], y2 = result[i + 1];
336
- if (isPolylineSegmentBlocked(x1, y1, x2, y2, startBounds, clearance) || isPolylineSegmentBlocked(x1, y1, x2, y2, endBounds, clearance)) return Infinity;
337
- }
338
- return getPolylineScore(result, clearance);
311
+ function isPolylinePortAligned(port, stub, dx, dy) {
312
+ const offset = port >> 1 === POLYLINE_X ? dx : dy;
313
+ const sign = port & 1 ? 1 : -1;
314
+ return Math.abs(offset) <= POLYLINE_EPSILON ? stub > POLYLINE_EPSILON : offset * sign > 0;
339
315
  }
340
316
 
341
- function getPolylineRoute(result, startPoint, endPoint, startPort, endPort, startBounds, endBounds, clearance) {
342
- const startExit = [], endExit = [];
343
- getPolylineExit(startPoint, startBounds, startPort, clearance, startExit);
344
- getPolylineExit(endPoint, endBounds, endPort, clearance, endExit);
345
- const sx = startExit[0], sy = startExit[1], ex = endExit[0], ey = endExit[1];
346
- const startAxis = startPort >> 1, endAxis = endPort >> 1;
347
- const startSign = startPort & 1 ? 1 : -1, endSign = endPort & 1 ? 1 : -1;
317
+ function isPolylineMidpointAligned(port, stub, dx, dy, axis) {
318
+ if (port === undefined) return true;
319
+ if (axis === POLYLINE_X && Math.abs(dx / 2) > POLYLINE_EPSILON) return isPolylinePortAligned(port, stub, dx, 0);
320
+ if (axis === POLYLINE_Y && Math.abs(dy / 2) > POLYLINE_EPSILON) return isPolylinePortAligned(port, stub, 0, dy);
321
+ if (Math.abs(dx) <= POLYLINE_EPSILON && Math.abs(dy) <= POLYLINE_EPSILON) return true;
322
+ return isPolylinePortAligned(port, stub, dx, dy);
323
+ }
324
+
325
+ function isPolylineApproachAligned(points, port) {
326
+ if (port === undefined) return true;
327
+ const last = points.length - 2, x = points[last], y = points[last + 1];
328
+ for (let i = last - 2; i >= 0; i -= 2) {
329
+ const dx = points[i] - x, dy = points[i + 1] - y;
330
+ if (Math.abs(dx) > POLYLINE_EPSILON || Math.abs(dy) > POLYLINE_EPSILON) return isPolylinePortAligned(port, 1, dx, dy);
331
+ }
332
+ return true;
333
+ }
334
+
335
+ function getPolylineRoute(result, startPoint, endPoint, startPort, endPort, startBounds, endBounds, clearance, strictPorts, approachPort) {
336
+ const startExit = getPolylineExit(startPoint, startBounds, startPort, clearance);
337
+ const endExit = endPort === undefined ? endPoint : getPolylineExit(endPoint, endBounds, endPort, clearance);
338
+ const {x: sx, y: sy} = startExit, {x: ex, y: ey} = endExit;
348
339
  const startStub = Math.abs(sx - startPoint.x) + Math.abs(sy - startPoint.y);
349
340
  const endStub = Math.abs(ex - endPoint.x) + Math.abs(ey - endPoint.y);
350
341
  if (isPolylineSegmentBlocked(startPoint.x, startPoint.y, sx, sy, endBounds, clearance) || isPolylineSegmentBlocked(endPoint.x, endPoint.y, ex, ey, startBounds, clearance)) return Infinity;
351
- const midpointAxis = getPolylineMidpointAxis(startPort, endPort, sx, sy, ex, ey);
352
- const midpointScore = getPolylineMidpointRoute(result, startPoint, endPoint, sx, sy, ex, ey, midpointAxis, startBounds, endBounds, clearance);
353
- if (midpointScore < Infinity) return midpointScore;
342
+ if (endPort === undefined && (isPolylinePointBlocked(ex, ey, startBounds, clearance) || isPolylinePointBlocked(ex, ey, endBounds, clearance))) return Infinity;
343
+ const axis = endPort === undefined ? startPort >> 1 : getPolylineMidpointAxis(startPort, endPort, sx, sy, ex, ey);
344
+ const dx = ex - sx, dy = ey - sy;
345
+ result.length = 0;
346
+ result.push(startPoint.x, startPoint.y, sx, sy);
347
+ if ((!strictPorts || isPolylineMidpointAligned(startPort, startStub, dx, dy, axis) && isPolylineMidpointAligned(endPort, endStub, -dx, -dy, axis)) && isPolylineMidpointAligned(approachPort, 1, -dx, -dy, axis)) {
348
+ const mx = (sx + ex) / 2, my = (sy + ey) / 2;
349
+ if (axis === POLYLINE_X) result.push(mx, sy, mx, ey); else result.push(sx, my, ex, my);
350
+ result.push(ex, ey, endPoint.x, endPoint.y);
351
+ for (let i = 4; i < result.length - 2; i += 2) {
352
+ if (isPolylineSegmentBlocked(result[i - 2], result[i - 1], result[i], result[i + 1], startBounds, clearance) || isPolylineSegmentBlocked(result[i - 2], result[i - 1], result[i], result[i + 1], endBounds, clearance)) {
353
+ result.length = 4;
354
+ break;
355
+ }
356
+ }
357
+ if (result.length > 4 && isPolylineApproachAligned(result, approachPort)) return getPolylineScore(result, clearance);
358
+ result.length = 4;
359
+ }
360
+ const score = findPolylineGridRoute(result, startExit, endExit, startPort, endPort, startBounds, endBounds, clearance, axis, startStub, endStub, strictPorts, approachPort);
361
+ if (score === Infinity) return score;
362
+ result.push(endPoint.x, endPoint.y);
363
+ return isPolylineApproachAligned(result, approachPort) ? score + startStub + endStub : Infinity;
364
+ }
365
+
366
+ function findPolylineGridRoute(result, startExit, endExit, startPort, endPort, startBounds, endBounds, clearance, midpointAxis, startStub, endStub, strictPorts, approachPort) {
367
+ const {x: sx, y: sy} = startExit, {x: ex, y: ey} = endExit;
354
368
  const margin = Math.max(clearance, POLYLINE_MIN_SEGMENT) * 2;
355
369
  const xs = [ sx, ex, (sx + ex) / 2 ], ys = [ sy, ey, (sy + ey) / 2 ];
356
370
  addPolylineBoundsCoordinates(xs, ys, startBounds, clearance, margin);
357
371
  addPolylineBoundsCoordinates(xs, ys, endBounds, clearance, margin);
358
- let minX = Math.min(...xs), maxX = Math.max(...xs);
359
- let minY = Math.min(...ys), maxY = Math.max(...ys);
360
- xs.push(minX - margin * 2, maxX + margin * 2);
361
- ys.push(minY - margin * 2, maxY + margin * 2);
372
+ xs.push(Math.min(...xs) - margin * 2, Math.max(...xs) + margin * 2);
373
+ ys.push(Math.min(...ys) - margin * 2, Math.max(...ys) + margin * 2);
362
374
  sortPolylineCoordinates(xs);
363
375
  sortPolylineCoordinates(ys);
364
376
  const nx = xs.length, ny = ys.length;
@@ -372,53 +384,49 @@ function getPolylineRoute(result, startPoint, endPoint, startPort, endPort, star
372
384
  previous.fill(-1);
373
385
  const startState = startNode * 3;
374
386
  distance[startState] = 0;
387
+ const pending = [ startState ];
375
388
  const turnCost = Math.max(POLYLINE_MIN_SEGMENT, clearance * POLYLINE_TURN_WEIGHT);
389
+ const preferredCoordinate = midpointAxis === POLYLINE_X ? (sx + ex) / 2 : (sy + ey) / 2;
376
390
  let currentState = -1, currentNode = -1, currentAxis = 0;
377
391
  let currentX = 0, currentY = 0, currentDistance = 0;
378
- const relax = (nextXIndex, nextYIndex, axis, sign) => {
392
+ const relax = (nextXIndex, nextYIndex, axis) => {
379
393
  const nextX = xs[nextXIndex], nextY = ys[nextYIndex];
380
394
  const nextNode = nextYIndex * nx + nextXIndex;
381
- if (isPolylinePointBlocked(nextX, nextY, startBounds, clearance) || isPolylinePointBlocked(nextX, nextY, endBounds, clearance)) return;
382
- if (isPolylineSegmentBlocked(currentX, currentY, nextX, nextY, startBounds, clearance) || isPolylineSegmentBlocked(currentX, currentY, nextX, nextY, endBounds, clearance)) return;
383
- if (currentState === startState) {
384
- if (axis === startAxis + 1) {
385
- if (sign !== startSign) return;
386
- } else if (startStub <= POLYLINE_EPSILON) return;
387
- }
388
- if (nextNode === endNode) {
389
- if (axis === endAxis + 1) {
390
- if (sign !== -endSign) return;
391
- } else if (endStub <= POLYLINE_EPSILON) return;
392
- }
395
+ const dx = nextX - currentX, dy = nextY - currentY;
396
+ if (nextNode === startNode) return;
397
+ if (approachPort !== undefined && nextNode === endNode && !isPolylinePortAligned(approachPort, 1, -dx, -dy)) return;
398
+ if (strictPorts && (currentState === startState && !isPolylinePortAligned(startPort, startStub, dx, dy) || endPort !== undefined && nextNode === endNode && !isPolylinePortAligned(endPort, endStub, -dx, -dy))) return;
399
+ if (isPolylinePointBlocked(nextX, nextY, startBounds, clearance) || isPolylinePointBlocked(nextX, nextY, endBounds, clearance) || isPolylineSegmentBlocked(currentX, currentY, nextX, nextY, startBounds, clearance) || isPolylineSegmentBlocked(currentX, currentY, nextX, nextY, endBounds, clearance)) return;
393
400
  const nextState = nextNode * 3 + axis;
394
401
  if (visited[nextState]) return;
395
- const segmentLength = Math.abs(nextX - currentX) + Math.abs(nextY - currentY);
396
- let cost = currentDistance + segmentLength;
402
+ let cost = currentDistance + (Math.abs(dx) + Math.abs(dy));
397
403
  if (currentAxis && currentAxis !== axis) {
398
404
  cost += turnCost;
399
405
  const turnCoordinate = currentAxis === POLYLINE_X + 1 ? currentX : currentY;
400
- const preferredCoordinate = midpointAxis === POLYLINE_X ? (sx + ex) / 2 : (sy + ey) / 2;
401
406
  if (Math.abs(turnCoordinate - preferredCoordinate) > POLYLINE_EPSILON) cost += turnCost * 2;
402
407
  }
403
408
  if (cost < distance[nextState]) {
409
+ if (distance[nextState] === Infinity) pending.push(nextState);
404
410
  distance[nextState] = cost;
405
411
  previous[nextState] = currentState;
406
412
  }
407
413
  };
408
414
  let bestState = -1;
409
- for (let iteration = 0; iteration < total; iteration++) {
410
- let minDistance = Infinity, state = -1;
411
- for (let i = 0; i < total; i++) {
412
- if (!visited[i] && distance[i] < minDistance) {
413
- minDistance = distance[i];
414
- state = i;
415
+ while (pending.length) {
416
+ let index = 0, state = pending[0];
417
+ for (let i = 1; i < pending.length; i++) {
418
+ const next = pending[i];
419
+ if (distance[next] < distance[state] || distance[next] === distance[state] && next < state) {
420
+ index = i;
421
+ state = next;
415
422
  }
416
423
  }
417
- if (state < 0) break;
424
+ pending[index] = pending[pending.length - 1];
425
+ pending.pop();
418
426
  currentState = state;
419
427
  currentNode = Math.floor(state / 3);
420
428
  currentAxis = state % 3;
421
- currentDistance = minDistance;
429
+ currentDistance = distance[state];
422
430
  visited[state] = 1;
423
431
  if (currentNode === endNode) {
424
432
  bestState = state;
@@ -427,10 +435,10 @@ function getPolylineRoute(result, startPoint, endPoint, startPort, endPort, star
427
435
  const xIndex = currentNode % nx, yIndex = Math.floor(currentNode / nx);
428
436
  currentX = xs[xIndex];
429
437
  currentY = ys[yIndex];
430
- if (xIndex > 0) relax(xIndex - 1, yIndex, POLYLINE_X + 1, -1);
431
- if (xIndex < nx - 1) relax(xIndex + 1, yIndex, POLYLINE_X + 1, 1);
432
- if (yIndex > 0) relax(xIndex, yIndex - 1, POLYLINE_Y + 1, -1);
433
- if (yIndex < ny - 1) relax(xIndex, yIndex + 1, POLYLINE_Y + 1, 1);
438
+ if (xIndex > 0) relax(xIndex - 1, yIndex, POLYLINE_X + 1);
439
+ if (xIndex < nx - 1) relax(xIndex + 1, yIndex, POLYLINE_X + 1);
440
+ if (yIndex > 0) relax(xIndex, yIndex - 1, POLYLINE_Y + 1);
441
+ if (yIndex < ny - 1) relax(xIndex, yIndex + 1, POLYLINE_Y + 1);
434
442
  }
435
443
  if (bestState < 0) return Infinity;
436
444
  const reverse = [];
@@ -442,59 +450,83 @@ function getPolylineRoute(result, startPoint, endPoint, startPort, endPort, star
442
450
  state = previous[state];
443
451
  }
444
452
  if (state !== startState) return Infinity;
445
- result.length = 0;
446
- result.push(startPoint.x, startPoint.y, sx, sy);
447
453
  for (let i = reverse.length - 4; i >= 0; i -= 2) result.push(reverse[i], reverse[i + 1]);
448
- result.push(endPoint.x, endPoint.y);
449
- return distance[bestState] + startStub + endStub;
454
+ return distance[bestState];
450
455
  }
451
456
 
452
- function appendPolylinePoint(points, x, y) {
453
- const length = points.length;
454
- if (length >= 2 && Math.abs(points[length - 2] - x) <= POLYLINE_EPSILON && Math.abs(points[length - 1] - y) <= POLYLINE_EPSILON) return;
455
- points.push(x, y);
457
+ function getPolylineFallback(start, end, port, startBounds, endBounds) {
458
+ const {x: sx, y: sy} = start, {x: ex, y: ey} = end;
459
+ if (sx === ex || sy === ey) return [ sx, sy, ex, ey ];
460
+ const horizontal = port >> 1 === POLYLINE_X;
461
+ const crosses = (x, y) => {
462
+ let count = 0;
463
+ if (isPolylineSegmentBlocked(sx, sy, x, y, startBounds, 0)) count++;
464
+ if (isPolylineSegmentBlocked(x, y, ex, ey, startBounds, 0)) count++;
465
+ if (isPolylineSegmentBlocked(sx, sy, x, y, endBounds, 0)) count++;
466
+ if (isPolylineSegmentBlocked(x, y, ex, ey, endBounds, 0)) count++;
467
+ return count;
468
+ };
469
+ const xy = crosses(ex, sy), yx = crosses(sx, ey);
470
+ return xy < yx || xy === yx && horizontal ? [ sx, sy, ex, sy, ex, ey ] : [ sx, sy, sx, ey, ex, ey ];
456
471
  }
457
472
 
458
- function appendPolylineOrthogonal(points, x1, y1, x2, y2, firstAxis = POLYLINE_X) {
459
- if (Math.abs(x1 - x2) > POLYLINE_EPSILON && Math.abs(y1 - y2) > POLYLINE_EPSILON) {
460
- if (firstAxis === POLYLINE_X) {
461
- const midX = (x1 + x2) / 2;
462
- appendPolylinePoint(points, midX, y1);
463
- appendPolylinePoint(points, midX, y2);
464
- } else {
465
- const midY = (y1 + y2) / 2;
466
- appendPolylinePoint(points, x1, midY);
467
- appendPolylinePoint(points, x2, midY);
473
+ function getBestPolyline(startPoint, endPoint, startDirection, endDirection, startBounds, endBounds, clearance, approachPort) {
474
+ const startPorts = getPolylinePorts(startDirection, startPoint, endPoint, startBounds, endDirection === undefined ? undefined : endBounds);
475
+ const endPorts = endDirection === undefined ? [ undefined ] : getPolylinePorts(endDirection, endPoint, startPoint, endBounds, startBounds);
476
+ let candidate = [], best = [], bestScore = Infinity;
477
+ for (let pass = clearance ? 0 : 1; pass < 3 && !best.length; pass++) {
478
+ const gap = pass ? 0 : clearance;
479
+ for (let i = 0; i < startPorts.length; i++) {
480
+ for (let j = 0; j < endPorts.length; j++) {
481
+ const score = getPolylineRoute(candidate, startPoint, endPoint, startPorts[i], endPorts[j], startBounds, endBounds, gap, pass < 2, approachPort);
482
+ if (score < bestScore) {
483
+ bestScore = score;
484
+ const previous = best;
485
+ best = candidate;
486
+ candidate = previous;
487
+ }
488
+ }
468
489
  }
469
490
  }
470
- appendPolylinePoint(points, x2, y2);
491
+ if (!best.length) return getPolylineFallback(startPoint, endPoint, startPorts[0], startBounds, endBounds);
492
+ simplifyPolyline(best);
493
+ const last = best.length - 2;
494
+ if (best[last] !== endPoint.x || best[last + 1] !== endPoint.y) best.push(endPoint.x, endPoint.y);
495
+ return best;
471
496
  }
472
497
 
473
- function getPolylineEditPath(result, startPoint, endPoint, startPort, endPort, startBounds, endBounds, points, clearance) {
474
- if (points.length % 2) return Infinity;
475
- for (let i = 0; i < points.length; i++) if (!Number.isFinite(points[i])) return Infinity;
476
- const startExit = [], endExit = [];
477
- getPolylineExit(startPoint, startBounds, startPort, clearance, startExit);
478
- getPolylineExit(endPoint, endBounds, endPort, clearance, endExit);
479
- const sx = startExit[0], sy = startExit[1], ex = endExit[0], ey = endExit[1];
480
- if (isPolylineSegmentBlocked(startPoint.x, startPoint.y, sx, sy, endBounds, clearance) || isPolylineSegmentBlocked(endPoint.x, endPoint.y, ex, ey, startBounds, clearance)) return Infinity;
481
- result.length = 0;
482
- appendPolylinePoint(result, startPoint.x, startPoint.y);
483
- appendPolylinePoint(result, sx, sy);
484
- let x = sx, y = sy;
485
- for (let i = 0; i < points.length; i += 2) {
486
- const nx = points[i], ny = points[i + 1];
487
- appendPolylineOrthogonal(result, x, y, nx, ny, i === 0 && clearance === 0 ? startPort >> 1 : POLYLINE_X);
488
- x = nx;
489
- y = ny;
490
- }
491
- const endAxis = endPort >> 1;
492
- if (Math.abs(x - ex) > POLYLINE_EPSILON && Math.abs(y - ey) > POLYLINE_EPSILON) {
493
- if (endAxis === POLYLINE_X) appendPolylinePoint(result, x, ey); else appendPolylinePoint(result, ex, y);
494
- }
495
- appendPolylinePoint(result, ex, ey);
496
- appendPolylinePoint(result, endPoint.x, endPoint.y);
497
- return getPolylineScore(result, clearance);
498
+ function getPolylineEditSide(point, waypoint, direction, bounds, otherBounds, clearance, points, index, step) {
499
+ if (point.x === waypoint.x && point.y === waypoint.y) return [];
500
+ let approachPort;
501
+ for (let i = index + step; i >= 0 && i < points.length; i += step) {
502
+ const dx = points[i] - waypoint.x, dy = points[i + 1] - waypoint.y;
503
+ if (Math.abs(dx) <= POLYLINE_EPSILON && Math.abs(dy) <= POLYLINE_EPSILON) continue;
504
+ if (Math.abs(dy) <= POLYLINE_EPSILON) approachPort = dx > 0 ? 0 : 1; else if (Math.abs(dx) <= POLYLINE_EPSILON) approachPort = dy > 0 ? 2 : 3;
505
+ break;
506
+ }
507
+ const side = getBestPolyline(point, waypoint, direction, undefined, bounds, otherBounds, clearance, approachPort);
508
+ side.length -= 2;
509
+ return side;
510
+ }
511
+
512
+ function drawPolylineEditPath(path, startPoint, endPoint, startDirection, endDirection, startBounds, endBounds, clearance, points) {
513
+ const length = points.length, last = length - 2;
514
+ if (length % 2) return false;
515
+ for (let i = 0; i < length; i++) if (!Number.isFinite(points[i])) return false;
516
+ const start = getPolylineEditSide(startPoint, {
517
+ x: points[0],
518
+ y: points[1]
519
+ }, startDirection, startBounds, endBounds, clearance, points, 0, 2);
520
+ const end = getPolylineEditSide(endPoint, {
521
+ x: points[last],
522
+ y: points[last + 1]
523
+ }, endDirection, endBounds, startBounds, clearance, points, last, -2);
524
+ const first = start.length ? start : points;
525
+ moveTo$1(path, first[0], first[1]);
526
+ for (let i = 2; i < start.length; i += 2) lineTo$1(path, start[i], start[i + 1]);
527
+ for (let i = start.length ? 0 : 2; i < length; i += 2) lineTo$1(path, points[i], points[i + 1]);
528
+ for (let i = end.length - 2; i >= 0; i -= 2) lineTo$1(path, end[i], end[i + 1]);
529
+ return true;
498
530
  }
499
531
 
500
532
  function getPolylineScore(points, clearance) {
@@ -537,26 +569,8 @@ function drawPolyline(path, startPoint, endPoint, startDirection, endDirection,
537
569
  if (startBounds && (!Number.isFinite(startBounds.x) || !Number.isFinite(startBounds.y) || !Number.isFinite(startBounds.width) || !Number.isFinite(startBounds.height) || startBounds.width < 0 || startBounds.height < 0)) return false;
538
570
  if (endBounds && (!Number.isFinite(endBounds.x) || !Number.isFinite(endBounds.y) || !Number.isFinite(endBounds.width) || !Number.isFinite(endBounds.height) || endBounds.width < 0 || endBounds.height < 0)) return false;
539
571
  clearance = Number.isFinite(clearance) ? Math.max(0, clearance) : 8;
540
- const startPorts = [], endPorts = [];
541
- const startCount = getPolylinePorts(startDirection, startPoint, endPoint, startBounds, endBounds, startPorts);
542
- const endCount = getPolylinePorts(endDirection, endPoint, startPoint, endBounds, startBounds, endPorts);
543
- const candidate = [], best = [];
544
- let bestScore = Infinity;
545
- for (let pass = 0; pass < 2 && bestScore === Infinity; pass++) {
546
- const currentClearance = pass === 0 ? clearance : 0;
547
- for (let i = 0; i < startCount; i++) {
548
- for (let j = 0; j < endCount; j++) {
549
- const score = points !== undefined ? getPolylineEditPath(candidate, startPoint, endPoint, startPorts[i], endPorts[j], startBounds, endBounds, points, currentClearance) : getPolylineRoute(candidate, startPoint, endPoint, startPorts[i], endPorts[j], startBounds, endBounds, currentClearance);
550
- if (score < bestScore) {
551
- bestScore = score;
552
- best.length = 0;
553
- for (let k = 0; k < candidate.length; k++) best.push(candidate[k]);
554
- }
555
- }
556
- }
557
- }
558
- if (!best.length) return false;
559
- if (points === undefined) simplifyPolyline(best);
572
+ if (points === null || points === void 0 ? void 0 : points.length) return drawPolylineEditPath(path, startPoint, endPoint, startDirection, endDirection, startBounds, endBounds, clearance, points);
573
+ const best = getBestPolyline(startPoint, endPoint, startDirection, endDirection, startBounds, endBounds, clearance);
560
574
  moveTo$1(path, best[0], best[1]);
561
575
  for (let i = 2; i < best.length; i += 2) lineTo$1(path, best[i], best[i + 1]);
562
576
  return true;