All files angleMeasureGeometry.js

97.4% Statements 75/77
53.33% Branches 8/15
100% Functions 6/6
97.4% Lines 75/77

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 7818x 18x 18x 1x 1x 12x 12x 1x 1x 2x 2x 2x 2x 2x 2x     2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x  
function clamp01(value) {
  return Math.max(0, Math.min(1, Number(value) || 0));
}
 
export function round3(value) {
  return Number.parseFloat(Number(value).toFixed(3));
}
 
export function getAngleLabelBasePosition(x1, y1, xm, ym, x2, y2) {
  const va = { x: Number(x1) - Number(xm), y: Number(y1) - Number(ym) };
  const vb = { x: Number(x2) - Number(xm), y: Number(y2) - Number(ym) };
  const lenA = Math.hypot(va.x, va.y);
  const lenB = Math.hypot(vb.x, vb.y);
 
  if (lenA <= 1e-6 || lenB <= 1e-6) {
    return { x: clamp01(xm), y: clamp01(Number(ym) - 0.14) };
  }
 
  const unit = {
    x: (va.x / lenA) + (vb.x / lenB),
    y: (va.y / lenA) + (vb.y / lenB),
  };
  const unitLength = Math.hypot(unit.x, unit.y);
  const bisector = unitLength <= 1e-6
    ? { x: 0, y: -1 }
    : { x: unit.x / unitLength, y: unit.y / unitLength };
 
  return {
    x: clamp01(Number(xm) + bisector.x * 0.14),
    y: clamp01(Number(ym) + bisector.y * 0.14),
  };
}
 
export function getAngleLabelPosition(points, labelDx = 0, labelDy = 0) {
  const base = getAngleLabelBasePosition(points.x1, points.y1, points.xm, points.ym, points.x2, points.y2);
  return {
    x: clamp01(base.x + (Number(labelDx) || 0)),
    y: clamp01(base.y + (Number(labelDy) || 0)),
  };
}
 
export function moveAngleWidget(points, dx, dy) {
  const nextDx = Number(dx) || 0;
  const nextDy = Number(dy) || 0;
  const xs = [points.x1, points.xm, points.x2];
  const ys = [points.y1, points.ym, points.y2];
  const minX = Math.min(...xs);
  const maxX = Math.max(...xs);
  const minY = Math.min(...ys);
  const maxY = Math.max(...ys);
  const clampedDx = Math.max(-minX, Math.min(1 - maxX, nextDx));
  const clampedDy = Math.max(-minY, Math.min(1 - maxY, nextDy));
 
  return {
    x1: round3(clamp01(points.x1 + clampedDx)),
    y1: round3(clamp01(points.y1 + clampedDy)),
    xm: round3(clamp01(points.xm + clampedDx)),
    ym: round3(clamp01(points.ym + clampedDy)),
    x2: round3(clamp01(points.x2 + clampedDx)),
    y2: round3(clamp01(points.y2 + clampedDy)),
  };
}
 
export function measureAngleDegrees(x1, y1, xm, ym, x2, y2) {
  const ax = Number(x1) - Number(xm);
  const ay = Number(y1) - Number(ym);
  const bx = Number(x2) - Number(xm);
  const by = Number(y2) - Number(ym);
  const lenA = Math.hypot(ax, ay);
  const lenB = Math.hypot(bx, by);
 
  if (lenA <= 1e-12 || lenB <= 1e-12) return 0;
 
  const cosTheta = ((ax * bx) + (ay * by)) / (lenA * lenB);
  const clamped = Math.max(-1, Math.min(1, cosTheta));
  return Math.acos(clamped) * (180 / Math.PI);
}