function circlineValidSectors()

in packages/charts/src/chart_types/partition_chart/layout/utils/circline_geometry.ts [65:116]


function circlineValidSectors(refC: CirclinePredicate, c: CirclineArc): CirclineArc[] {
  const { inside } = refC;
  const { x, y, r, from, to } = c;
  const fullContainment = fullyContained(refC, c);
  const fullyOutside = noOverlap(refC, c) || fullyContained(c, refC);

  // handle clear cases

  // nothing kept:
  if ((inside && fullContainment) || (!inside && fullyOutside)) {
    return [];
  }

  // the entire sector is kept
  if ((inside && fullyOutside) || (!inside && fullContainment)) {
    return [c];
  }

  // now we know there's intersection and we're supposed to get back two distinct points
  const circlineIntersections = circlineIntersect(refC, c);
  // These conditions don't happen; kept for documentation purposes:
  // if (circlineIntersections.length !== 2) throw new Error('Problem in intersection calculation.')
  // if (from > to) throw new Error('From/to problem in intersection calculation.')
  const [p1, p2] = circlineIntersections;
  if (!p1 || !p2) return [];
  const aPre1 = Math.atan2(p1.y - c.y, p1.x - c.x);
  const aPre2 = Math.atan2(p2.y - c.y, p2.x - c.x);
  const a1p = Math.max(from, Math.min(to, aPre1 < 0 ? aPre1 + TAU : aPre1));
  const a2p = Math.max(from, Math.min(to, aPre2 < 0 ? aPre2 + TAU : aPre2));
  const a1 = Math.min(a1p, a2p);
  const a2 = a1p === a2p ? TAU : Math.max(a1p, a2p); // make a2 drop out in next step

  // imperative, slightly optimized buildup of `breakpoints` as it's in the hot loop:
  const breakpoints = [from];
  if (from < a1 && a1 < to) breakpoints.push(a1);
  if (from < a2 && a2 < to) breakpoints.push(a2);
  breakpoints.push(to);

  const predicate = inside ? noOverlap : fullyContained;

  // imperative, slightly optimized buildup of `result` as it's in the hot loop:
  const result = [];
  for (let i = 0; i < breakpoints.length - 1; i++) {
    const from = breakpoints[i] ?? 0;
    const to = breakpoints[i + 1] ?? 0;
    const midAngle = (from + to) / 2; // no winding clip ie. `meanAngle()` would be wrong here
    const xx = x + r * Math.cos(midAngle);
    const yy = y + r * Math.sin(midAngle);
    if (predicate(refC, { x: xx, y: yy, r: 0 })) result.push({ x, y, r, from, to });
  }
  return result;
}