import {
  Vec2d,
  assert,
  average,
  precise,
  shortAngleDist,
  toDomPrecision
} from "@cmpd/editor";
import { getStrokeOutlineTracks } from "./getStrokeOutlinePoints.mjs";
import { getStrokePoints } from "./getStrokePoints.mjs";
import { setStrokePointRadii } from "./setStrokePointRadii.mjs";
function svgInk(rawInputPoints, options = {}) {
  const { start = {}, end = {} } = options;
  const { cap: capStart = true } = start;
  const { cap: capEnd = true } = end;
  assert(!start.taper && !end.taper, "cap taper not supported here");
  assert(!start.easing && !end.easing, "cap easing not supported here");
  assert(capStart && capEnd, "cap must be true");
  const points = getStrokePoints(rawInputPoints, options);
  setStrokePointRadii(points, options);
  const partitions = partitionAtElbows(points);
  let svg = "";
  for (const partition of partitions) {
    svg += renderPartition(partition, options);
  }
  return svg;
}
function partitionAtElbows(points) {
  if (points.length <= 2)
    return [points];
  const result = [];
  let currentPartition = [points[0]];
  for (let i = 1; i < points.length - 1; i++) {
    const prevPoint = points[i - 1];
    const thisPoint = points[i];
    const nextPoint = points[i + 1];
    const prevAngle = Vec2d.Angle(prevPoint.point, thisPoint.point);
    const nextAngle = Vec2d.Angle(thisPoint.point, nextPoint.point);
    const acuteness = Math.abs(shortAngleDist(prevAngle, nextAngle)) / Math.PI;
    if (acuteness > 0.8) {
      const elbowPoint = {
        ...thisPoint,
        point: thisPoint.input
      };
      currentPartition.push(elbowPoint);
      result.push(cleanUpPartition(currentPartition));
      currentPartition = [elbowPoint];
      continue;
    }
    currentPartition.push(thisPoint);
    if (acuteness < 0.25) {
      continue;
    }
    const avgRadius = (prevPoint.radius + thisPoint.radius + nextPoint.radius) / 3;
    const incomingNormalizedDist = Vec2d.Dist(prevPoint.point, thisPoint.point) / avgRadius;
    const outgoingNormalizedDist = Vec2d.Dist(thisPoint.point, nextPoint.point) / avgRadius;
    const angularDist = incomingNormalizedDist + outgoingNormalizedDist;
    if (angularDist < 1.5) {
      currentPartition.push(thisPoint);
      result.push(cleanUpPartition(currentPartition));
      currentPartition = [thisPoint];
      continue;
    }
  }
  currentPartition.push(points[points.length - 1]);
  result.push(cleanUpPartition(currentPartition));
  return result;
}
function cleanUpPartition(partition) {
  const startPoint = partition[0];
  while (partition.length > 2) {
    const nextPoint = partition[1];
    const dist = Vec2d.Dist(startPoint.point, nextPoint.point);
    const avgRadius = (startPoint.radius + nextPoint.radius) / 2;
    if (dist < avgRadius * 0.5) {
      partition.splice(1, 1);
    } else {
      break;
    }
  }
  const endPoint = partition[partition.length - 1];
  while (partition.length > 2) {
    const prevPoint = partition[partition.length - 2];
    const dist = Vec2d.Dist(endPoint.point, prevPoint.point);
    const avgRadius = (endPoint.radius + prevPoint.radius) / 2;
    if (dist < avgRadius * 0.5) {
      partition.splice(partition.length - 2, 1);
    } else {
      break;
    }
  }
  if (partition.length > 1) {
    partition[0] = {
      ...partition[0],
      vector: Vec2d.FromAngle(Vec2d.Angle(partition[1].point, partition[0].point))
    };
    partition[partition.length - 1] = {
      ...partition[partition.length - 1],
      vector: Vec2d.FromAngle(
        Vec2d.Angle(partition[partition.length - 1].point, partition[partition.length - 2].point)
      )
    };
  }
  return partition;
}
function circlePath(cx, cy, r) {
  return "M " + cx + " " + cy + " m -" + r + ", 0 a " + r + "," + r + " 0 1,1 " + r * 2 + ",0 a " + r + "," + r + " 0 1,1 -" + r * 2 + ",0";
}
function renderPartition(strokePoints, options = {}) {
  if (strokePoints.length === 0)
    return "";
  if (strokePoints.length === 1) {
    return circlePath(strokePoints[0].point.x, strokePoints[0].point.y, strokePoints[0].radius);
  }
  const { left, right } = getStrokeOutlineTracks(strokePoints, options);
  right.reverse();
  let svg = `M${precise(left[0])}T`;
  for (let i = 1; i < left.length; i++) {
    svg += average(left[i - 1], left[i]);
  }
  {
    const point = strokePoints[strokePoints.length - 1];
    const radius = point.radius;
    const direction = point.vector.clone().per().neg();
    const arcStart = Vec2d.Add(point.point, Vec2d.Mul(direction, radius));
    const arcEnd = Vec2d.Add(point.point, Vec2d.Mul(direction, -radius));
    svg += `${precise(arcStart)}A${toDomPrecision(radius)},${toDomPrecision(
      radius
    )} 0 0 1 ${precise(arcEnd)}T`;
  }
  for (let i = 1; i < right.length; i++) {
    svg += average(right[i - 1], right[i]);
  }
  {
    const point = strokePoints[0];
    const radius = point.radius;
    const direction = point.vector.clone().per();
    const arcStart = Vec2d.Add(point.point, Vec2d.Mul(direction, radius));
    const arcEnd = Vec2d.Add(point.point, Vec2d.Mul(direction, -radius));
    svg += `${precise(arcStart)}A${toDomPrecision(radius)},${toDomPrecision(
      radius
    )} 0 0 1 ${precise(arcEnd)}Z`;
  }
  return svg;
}
export {
  renderPartition,
  svgInk
};
//# sourceMappingURL=svgInk.mjs.map
