@orbat-mapper/control-measures 0.29.0 → 0.29.1

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/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as DEFAULT_INFILTRATION_LANE_OPTIONS, $n as pointOnMidpointPerpendicularAxis, $t as DEFAULT_ENGAGEMENT_AREA_OPTIONS, A as DEFAULT_EVACUATE_OPTIONS, An as line27DrawRule, At as DEFAULT_GENERIC_POLYGON_OPTIONS, B as DEFAULT_FRONTAL_ATTACK_OPTIONS, Bn as staticPointDrawRule, Bt as DEFAULT_LIGHT_LINE_OPTIONS, C as DEFAULT_MINEFIELD_OPTIONS, Cn as MIL_STD_GREEN, Ct as DEFAULT_CLEAR_OPTIONS, D as DEFAULT_TURN_OPTIONS, Dn as computeInitialWidthPoint, Dt as DEFAULT_GENERIC_TEXT_OPTIONS, E as DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, En as calculateMetrics, Et as RADAR_SEARCH_DOCTRINE_STROKE_COLOR, F as DEFAULT_RELIEF_IN_PLACE_OPTIONS, Fn as line1DrawRule, Ft as DEFAULT_BYPASS_OPTIONS, G as DEFAULT_LINE_OF_DEPARTURE_CONTACT_OPTIONS, Gn as disruptDrawRule, Gt as DEFAULT_BATTLE_POSITION_OPTIONS, H as DEFAULT_FORTIFIED_LINE_OPTIONS, Hn as secureDrawRule, Ht as DEFAULT_BLOCK_ARROW_OPTIONS, I as DEFAULT_REARWARD_PASSAGE_OF_LINES_OPTIONS, In as ambushDrawRule, It as DEFAULT_BREACH_OPTIONS, J as DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, Jn as containDrawRule, Jt as DEFAULT_ANTITANK_WALL_OPTIONS, K as DEFAULT_LINE_OF_DEPARTURE_OPTIONS, Kn as blockDrawRule, Kt as DEFAULT_ATTACK_HELICOPTER_OPTIONS, L as DEFAULT_PENETRATE_OPTIONS, Ln as attackByFireDrawRule, Lt as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, M as DEFAULT_SECURE_OPTIONS, Mn as line24DrawRule, Mt as DEFAULT_GENERIC_CIRCLE_OPTIONS, N as DEFAULT_SCREEN_OPTIONS, Nn as line23DrawRule, Nt as DEFAULT_CLASSIC_ARROW_OPTIONS, O as DEFAULT_WITHDRAW_UNDER_PRESSURE_OPTIONS, On as supportByFireDrawRule, Ot as DEFAULT_GENERIC_SECTOR_OPTIONS, P as DEFAULT_RETIRE_OPTIONS, Pn as turnDrawRule, Pt as DEFAULT_CANALIZE_OPTIONS, Q as DEFAULT_HOLDING_LINE_OPTIONS, Qn as getMidpointPerpendicularSignedDistance, Qt as DEFAULT_MOBILE_DEFENSE_OPTIONS, R as DEFAULT_OCCUPY_OPTIONS, Rn as dynamicPointDrawRule, Rt as DEFAULT_GENERIC_C2_LINE_OPTIONS, S as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, Sn as DEFAULT_SYMBOL_COLOR, St as DEFAULT_ISOLATE_OPTIONS, T as DEFAULT_LANDING_ZONE_OPTIONS, Tn as axis1DrawRule, Tt as RADAR_SEARCH_DOCTRINE_FILL_COLOR, U as DEFAULT_PROBABLE_LINE_OF_DEPLOYMENT_OPTIONS, Un as penetrateDrawRule, Ut as DEFAULT_BLOCK_OPTIONS, V as DEFAULT_FORTIFIED_AREA_OPTIONS, Vn as point12DrawRule, Vt as DEFAULT_BOUNDARY_OPTIONS, W as PROBABLE_LINE_OF_DEPLOYMENT_DASH, Wn as occupyDrawRule, Wt as DEFAULT_CONTAIN_OPTIONS, X as DEFAULT_FORWARD_EDGE_OF_BATTLE_AREA_OPTIONS, Xn as computeDefaultMidpointPerpendicularPoint, Xt as DEFAULT_ASSEMBLY_AREA_OPTIONS, Y as DEFAULT_HANDOVER_LINE_OPTIONS, Yn as area27DrawRule, Yt as DEFAULT_ANTITANK_DITCH_OPTIONS, Z as DEFAULT_RELEASE_LINE_OPTIONS, Zn as createMidpointPerpendicularDrawRule, Zt as DEFAULT_AREA_OF_OPERATIONS_OPTIONS, _ as SECONDARY_DIRECTION_OF_FIRE_DASH, _n as DEFAULT_LINE_JOIN, _t as DEFAULT_COUNTERATTACK_BY_FIRE_OPTIONS, a as CONTROL_MEASURE_IDS, an as canonicalTextAmplifierKey, ar as sphericalBearing, at as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, b as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, bn as DEFAULT_STROKE_WIDTH_CSS_PIXELS, bt as DEFAULT_CORDON_AND_SEARCH_OPTIONS, c as getControlMeasureMetadata, cn as DEFAULT_AMBUSH_OPTIONS, cr as getMetersPerPixel, ct as DEFAULT_GUARD_OPTIONS, d as listControlMeasureMetadata, dn as DEFAULT_NEUTRALIZE_OPTIONS, dt as DEFAULT_DISRUPT_MISSION_TASK_OPTIONS, en as DEFAULT_AREA_DEFENSE_OPTIONS, er as snapToMidpointPerpendicular, et as DEFAULT_BRIDGEHEAD_LINE_OPTIONS, f as DEFAULT_TURNING_MOVEMENT_OPTIONS, fn as DEFAULT_SUPPRESS_OPTIONS, ft as DEFAULT_DISENGAGE_OPTIONS, g as DEFAULT_SECONDARY_DIRECTION_OF_FIRE_OPTIONS, gn as DEFAULT_LINE_CAP, gt as DEFAULT_TACTICAL_ARROW_OPTIONS, h as DEFAULT_STRONG_POINT_OPTIONS, hn as DEFAULT_LABEL_SIZE_CLAMP_CSS_PIXELS, ht as DEFAULT_COVER_OPTIONS, i as resolveSymbolColor, in as TEXT_AMPLIFIER_FIELDS, ir as project, it as DEFAULT_FIX_OPTIONS, j as DEFAULT_SEIZE_OPTIONS, jn as line26DrawRule, jt as DEFAULT_GENERIC_LINE_OPTIONS, k as DEFAULT_WITHDRAW_OPTIONS, kn as polyline1DrawRule, kt as DEFAULT_GENERIC_RECTANGLE_OPTIONS, l as getControlMeasureMetadataByValue, ln as DEFAULT_AIRBORNE_ATTACK_OPTIONS, lr as isFiniteNumber, lt as createFollowAndSupport, m as DEFAULT_RETAIN_OPTIONS, mn as DEFAULT_LABEL_HEIGHT_CSS_PIXELS, mt as DEFAULT_DELAY_OPTIONS, n as resolveDefaultSymbolColor, nn as DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS, nr as EARTH_RADIUS, nt as DEFAULT_FLOT_OPTIONS, o as CONTROL_MEASURE_METADATA, on as normalizeTextAmplifiers, or as unproject, ot as DEFAULT_ENCIRCLEMENT_OPTIONS, p as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, pn as DEFAULT_DEFEAT_OPTIONS, pt as DEFAULT_DEMONSTRATE_OPTIONS, q as DEFAULT_LIMIT_OF_ADVANCE_OPTIONS, qn as centerRadiusDrawRule, qt as DEFAULT_ATTACK_BY_FIRE_OPTIONS, r as resolveStyleHints, rn as DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS, rr as haversineDistance, rt as DEFAULT_FIX_MISSION_TASK_OPTIONS, s as DEFINITIONS, sn as resolveAmplifierPlacement, sr as EPSILON, st as DEFAULT_DISRUPT_OPTIONS, t as renderControlMeasure, tn as DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS, tr as createBaselineFrame, tt as DEFAULT_PHASE_LINE_OPTIONS, u as getDefaultOptions, un as DEFAULT_DESTROY_OPTIONS, ur as roundToFixed, ut as createFollowAndAssume, v as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, vn as DEFAULT_PORTRAYAL, vt as DEFAULT_COUNTERATTACK_OPTIONS, w as DEFAULT_MAIN_ATTACK_OPTIONS, wn as rectangleDrawRule, wt as DEFAULT_RADAR_SEARCH_DOCTRINE_OPTIONS, x as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, xn as resolveConstructionMetersPerCssPixel, xt as DEFAULT_CORDON_AND_KNOCK_OPTIONS, y as DEFAULT_PICKUP_ZONE_OPTIONS, yn as DEFAULT_STROKE_DASH_CSS_PIXELS, yt as DEFAULT_SUPPORTING_ATTACK_OPTIONS, z as DEFAULT_MOVEMENT_TO_CONTACT_OPTIONS, zn as sectorDrawRule, zt as DEFAULT_ENGINEER_WORK_LINE_OPTIONS } from "./renderControlMeasure-ZpYrUlKM.mjs";
1
+ import { $ as DEFAULT_INFILTRATION_LANE_OPTIONS, $n as pointOnMidpointPerpendicularAxis, $t as DEFAULT_ENGAGEMENT_AREA_OPTIONS, A as DEFAULT_EVACUATE_OPTIONS, An as line27DrawRule, At as DEFAULT_GENERIC_POLYGON_OPTIONS, B as DEFAULT_FRONTAL_ATTACK_OPTIONS, Bn as staticPointDrawRule, Bt as DEFAULT_LIGHT_LINE_OPTIONS, C as DEFAULT_MINEFIELD_OPTIONS, Cn as MIL_STD_GREEN, Ct as DEFAULT_CLEAR_OPTIONS, D as DEFAULT_TURN_OPTIONS, Dn as computeInitialWidthPoint, Dt as DEFAULT_GENERIC_TEXT_OPTIONS, E as DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, En as calculateMetrics, Et as RADAR_SEARCH_DOCTRINE_STROKE_COLOR, F as DEFAULT_RELIEF_IN_PLACE_OPTIONS, Fn as line1DrawRule, Ft as DEFAULT_BYPASS_OPTIONS, G as DEFAULT_LINE_OF_DEPARTURE_CONTACT_OPTIONS, Gn as disruptDrawRule, Gt as DEFAULT_BATTLE_POSITION_OPTIONS, H as DEFAULT_FORTIFIED_LINE_OPTIONS, Hn as secureDrawRule, Ht as DEFAULT_BLOCK_ARROW_OPTIONS, I as DEFAULT_REARWARD_PASSAGE_OF_LINES_OPTIONS, In as ambushDrawRule, It as DEFAULT_BREACH_OPTIONS, J as DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, Jn as containDrawRule, Jt as DEFAULT_ANTITANK_WALL_OPTIONS, K as DEFAULT_LINE_OF_DEPARTURE_OPTIONS, Kn as blockDrawRule, Kt as DEFAULT_ATTACK_HELICOPTER_OPTIONS, L as DEFAULT_PENETRATE_OPTIONS, Ln as attackByFireDrawRule, Lt as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, M as DEFAULT_SECURE_OPTIONS, Mn as line24DrawRule, Mt as DEFAULT_GENERIC_CIRCLE_OPTIONS, N as DEFAULT_SCREEN_OPTIONS, Nn as line23DrawRule, Nt as DEFAULT_CLASSIC_ARROW_OPTIONS, O as DEFAULT_WITHDRAW_UNDER_PRESSURE_OPTIONS, On as supportByFireDrawRule, Ot as DEFAULT_GENERIC_SECTOR_OPTIONS, P as DEFAULT_RETIRE_OPTIONS, Pn as turnDrawRule, Pt as DEFAULT_CANALIZE_OPTIONS, Q as DEFAULT_HOLDING_LINE_OPTIONS, Qn as getMidpointPerpendicularSignedDistance, Qt as DEFAULT_MOBILE_DEFENSE_OPTIONS, R as DEFAULT_OCCUPY_OPTIONS, Rn as dynamicPointDrawRule, Rt as DEFAULT_GENERIC_C2_LINE_OPTIONS, S as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, Sn as DEFAULT_SYMBOL_COLOR, St as DEFAULT_ISOLATE_OPTIONS, T as DEFAULT_LANDING_ZONE_OPTIONS, Tn as axis1DrawRule, Tt as RADAR_SEARCH_DOCTRINE_FILL_COLOR, U as DEFAULT_PROBABLE_LINE_OF_DEPLOYMENT_OPTIONS, Un as penetrateDrawRule, Ut as DEFAULT_BLOCK_OPTIONS, V as DEFAULT_FORTIFIED_AREA_OPTIONS, Vn as point12DrawRule, Vt as DEFAULT_BOUNDARY_OPTIONS, W as PROBABLE_LINE_OF_DEPLOYMENT_DASH, Wn as occupyDrawRule, Wt as DEFAULT_CONTAIN_OPTIONS, X as DEFAULT_FORWARD_EDGE_OF_BATTLE_AREA_OPTIONS, Xn as computeDefaultMidpointPerpendicularPoint, Xt as DEFAULT_ASSEMBLY_AREA_OPTIONS, Y as DEFAULT_HANDOVER_LINE_OPTIONS, Yn as area27DrawRule, Yt as DEFAULT_ANTITANK_DITCH_OPTIONS, Z as DEFAULT_RELEASE_LINE_OPTIONS, Zn as createMidpointPerpendicularDrawRule, Zt as DEFAULT_AREA_OF_OPERATIONS_OPTIONS, _ as SECONDARY_DIRECTION_OF_FIRE_DASH, _n as DEFAULT_LINE_JOIN, _t as DEFAULT_COUNTERATTACK_BY_FIRE_OPTIONS, a as CONTROL_MEASURE_IDS, an as canonicalTextAmplifierKey, ar as sphericalBearing, at as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, b as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, bn as DEFAULT_STROKE_WIDTH_CSS_PIXELS, bt as DEFAULT_CORDON_AND_SEARCH_OPTIONS, c as getControlMeasureMetadata, cn as DEFAULT_AMBUSH_OPTIONS, cr as getMetersPerPixel, ct as DEFAULT_GUARD_OPTIONS, d as listControlMeasureMetadata, dn as DEFAULT_NEUTRALIZE_OPTIONS, dt as DEFAULT_DISRUPT_MISSION_TASK_OPTIONS, en as DEFAULT_AREA_DEFENSE_OPTIONS, er as snapToMidpointPerpendicular, et as DEFAULT_BRIDGEHEAD_LINE_OPTIONS, f as DEFAULT_TURNING_MOVEMENT_OPTIONS, fn as DEFAULT_SUPPRESS_OPTIONS, ft as DEFAULT_DISENGAGE_OPTIONS, g as DEFAULT_SECONDARY_DIRECTION_OF_FIRE_OPTIONS, gn as DEFAULT_LINE_CAP, gt as DEFAULT_TACTICAL_ARROW_OPTIONS, h as DEFAULT_STRONG_POINT_OPTIONS, hn as DEFAULT_LABEL_SIZE_CLAMP_CSS_PIXELS, ht as DEFAULT_COVER_OPTIONS, i as resolveSymbolColor, in as TEXT_AMPLIFIER_FIELDS, ir as project, it as DEFAULT_FIX_OPTIONS, j as DEFAULT_SEIZE_OPTIONS, jn as line26DrawRule, jt as DEFAULT_GENERIC_LINE_OPTIONS, k as DEFAULT_WITHDRAW_OPTIONS, kn as polyline1DrawRule, kt as DEFAULT_GENERIC_RECTANGLE_OPTIONS, l as getControlMeasureMetadataByValue, ln as DEFAULT_AIRBORNE_ATTACK_OPTIONS, lr as isFiniteNumber, lt as createFollowAndSupport, m as DEFAULT_RETAIN_OPTIONS, mn as DEFAULT_LABEL_HEIGHT_CSS_PIXELS, mt as DEFAULT_DELAY_OPTIONS, n as resolveDefaultSymbolColor, nn as DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS, nr as EARTH_RADIUS, nt as DEFAULT_FLOT_OPTIONS, o as CONTROL_MEASURE_METADATA, on as normalizeTextAmplifiers, or as unproject, ot as DEFAULT_ENCIRCLEMENT_OPTIONS, p as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, pn as DEFAULT_DEFEAT_OPTIONS, pt as DEFAULT_DEMONSTRATE_OPTIONS, q as DEFAULT_LIMIT_OF_ADVANCE_OPTIONS, qn as centerRadiusDrawRule, qt as DEFAULT_ATTACK_BY_FIRE_OPTIONS, r as resolveStyleHints, rn as DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS, rr as haversineDistance, rt as DEFAULT_FIX_MISSION_TASK_OPTIONS, s as DEFINITIONS, sn as resolveAmplifierPlacement, sr as EPSILON, st as DEFAULT_DISRUPT_OPTIONS, t as renderControlMeasure, tn as DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS, tr as createBaselineFrame, tt as DEFAULT_PHASE_LINE_OPTIONS, u as getDefaultOptions, un as DEFAULT_DESTROY_OPTIONS, ur as roundToFixed, ut as createFollowAndAssume, v as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, vn as DEFAULT_PORTRAYAL, vt as DEFAULT_COUNTERATTACK_OPTIONS, w as DEFAULT_MAIN_ATTACK_OPTIONS, wn as rectangleDrawRule, wt as DEFAULT_RADAR_SEARCH_DOCTRINE_OPTIONS, x as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, xn as resolveConstructionMetersPerCssPixel, xt as DEFAULT_CORDON_AND_KNOCK_OPTIONS, y as DEFAULT_PICKUP_ZONE_OPTIONS, yn as DEFAULT_STROKE_DASH_CSS_PIXELS, yt as DEFAULT_SUPPORTING_ATTACK_OPTIONS, z as DEFAULT_MOVEMENT_TO_CONTACT_OPTIONS, zn as sectorDrawRule, zt as DEFAULT_ENGINEER_WORK_LINE_OPTIONS } from "./renderControlMeasure-DsTDL15-.mjs";
2
2
  import { FILL_PATTERN_DEFINITIONS, NON_SOLID_FILL_PATTERNS, getFillPatternDefinition } from "./patterns.mjs";
3
3
  //#region src/metadata.ts
4
4
  const PARAMETER_PRESENTATION_TIERS = [
@@ -1,4 +1,4 @@
1
- import { s as DEFINITIONS, t as renderControlMeasure } from "../renderControlMeasure-ZpYrUlKM.mjs";
1
+ import { s as DEFINITIONS, t as renderControlMeasure } from "../renderControlMeasure-DsTDL15-.mjs";
2
2
  import { FILL_PATTERN_DEFINITIONS, NON_SOLID_FILL_PATTERNS } from "../patterns.mjs";
3
3
  //#region src/preview/index.ts
4
4
  /** Side length (SVG units) of the repeating non-mine tile in {@link PREVIEW_FILL_PATTERNS}. */
@@ -1590,33 +1590,56 @@ function evenlySpacePath(points, targetSegmentLength) {
1590
1590
  out.push(points[points.length - 1]);
1591
1591
  return out;
1592
1592
  }
1593
- /** One centripetal Catmull-Rom sample at parameter `t` over control points `p0..p3`. */
1594
- function catmullRomAt(p0, p1, p2, p3, t) {
1595
- const t2 = t * t;
1596
- const t3 = t2 * t;
1597
- return [.5 * (2 * p1[0] + (-p0[0] + p2[0]) * t + (2 * p0[0] - 5 * p1[0] + 4 * p2[0] - p3[0]) * t2 + (-p0[0] + 3 * p1[0] - 3 * p2[0] + p3[0]) * t3), .5 * (2 * p1[1] + (-p0[1] + p2[1]) * t + (2 * p0[1] - 5 * p1[1] + 4 * p2[1] - p3[1]) * t2 + (-p0[1] + 3 * p1[1] - 3 * p2[1] + p3[1]) * t3)];
1593
+ /**
1594
+ * Samples one centripetal (alpha = 0.5) Catmull-Rom segment from `p1` to `p2`
1595
+ * at `t = s / samples` for `s` in `[first, last]`, appending to `out`. Uses the
1596
+ * Hermite form (Yuksel et al.); centripetal knots keep the curve from
1597
+ * overshooting or looping next to a much shorter neighbouring segment.
1598
+ */
1599
+ function sampleCatmullRomSegment(out, [p0, p1, p2, p3], samples, first, last) {
1600
+ const knot = (a, b) => Math.sqrt(vecMag(vecSub(b, a)));
1601
+ const d1 = knot(p1, p2);
1602
+ const d0 = knot(p0, p1) || d1;
1603
+ const d2 = knot(p2, p3) || d1;
1604
+ const tangent = (a, b, c, da, db) => d1 < 1e-12 ? [0, 0] : [((b[0] - a[0]) / da - (c[0] - a[0]) / (da + db) + (c[0] - b[0]) / db) * d1, ((b[1] - a[1]) / da - (c[1] - a[1]) / (da + db) + (c[1] - b[1]) / db) * d1];
1605
+ const m1 = tangent(p0, p1, p2, d0, d1);
1606
+ const m2 = tangent(p1, p2, p3, d1, d2);
1607
+ for (let s = first; s <= last; s++) {
1608
+ const t = s / samples;
1609
+ const t2 = t * t;
1610
+ const t3 = t2 * t;
1611
+ const h00 = 2 * t3 - 3 * t2 + 1;
1612
+ const h10 = t3 - 2 * t2 + t;
1613
+ const h01 = -2 * t3 + 3 * t2;
1614
+ const h11 = t3 - t2;
1615
+ out.push([h00 * p1[0] + h10 * m1[0] + h01 * p2[0] + h11 * m2[0], h00 * p1[1] + h10 * m1[1] + h01 * p2[1] + h11 * m2[1]]);
1616
+ }
1598
1617
  }
1599
1618
  /**
1600
1619
  * Centripetal Catmull-Rom spline through `points`, sampled `samples` times per
1601
1620
  * segment. Endpoints are duplicated so the curve passes through them, so the
1602
- * first and last points are preserved exactly. With `samples <= 1` (or fewer
1603
- * than 3 points) it returns the input unchanged.
1621
+ * first and last points are preserved exactly. An `endDirection` instead makes
1622
+ * the curve arrive at the last point heading that way. With `samples <= 1` (or
1623
+ * fewer than 3 points) it returns the input unchanged.
1604
1624
  */
1605
- function catmullRom(points, samples) {
1625
+ function catmullRom(points, samples, endDirection) {
1606
1626
  if (points.length < 3 || samples <= 1) return points;
1627
+ const last = points[points.length - 1];
1628
+ const beforeLast = points[points.length - 2];
1629
+ const reach = vecMag(vecSub(last, beforeLast));
1630
+ const end = endDirection ? [last[0] + endDirection[0] * reach, last[1] + endDirection[1] * reach] : last;
1607
1631
  const pts = [
1608
1632
  points[0],
1609
1633
  ...points,
1610
- points[points.length - 1]
1634
+ end
1611
1635
  ];
1612
1636
  const out = [points[0]];
1613
- for (let i = 1; i < pts.length - 2; i++) {
1614
- const p0 = pts[i - 1];
1615
- const p1 = pts[i];
1616
- const p2 = pts[i + 1];
1617
- const p3 = pts[i + 2];
1618
- for (let s = 1; s <= samples; s++) out.push(catmullRomAt(p0, p1, p2, p3, s / samples));
1619
- }
1637
+ for (let i = 1; i < pts.length - 2; i++) sampleCatmullRomSegment(out, [
1638
+ pts[i - 1],
1639
+ pts[i],
1640
+ pts[i + 1],
1641
+ pts[i + 2]
1642
+ ], samples, 1, samples);
1620
1643
  return out;
1621
1644
  }
1622
1645
  /**
@@ -1629,13 +1652,12 @@ function closedCatmullRom(points, samples) {
1629
1652
  const n = points.length;
1630
1653
  if (n < 3 || samples <= 1) return points;
1631
1654
  const out = [];
1632
- for (let i = 0; i < n; i++) {
1633
- const p0 = points[(i - 1 + n) % n];
1634
- const p1 = points[i];
1635
- const p2 = points[(i + 1) % n];
1636
- const p3 = points[(i + 2) % n];
1637
- for (let s = 0; s < samples; s++) out.push(catmullRomAt(p0, p1, p2, p3, s / samples));
1638
- }
1655
+ for (let i = 0; i < n; i++) sampleCatmullRomSegment(out, [
1656
+ points[(i - 1 + n) % n],
1657
+ points[i],
1658
+ points[(i + 1) % n],
1659
+ points[(i + 2) % n]
1660
+ ], samples, 0, samples - 1);
1639
1661
  out.push([...out[0]]);
1640
1662
  return out;
1641
1663
  }
@@ -1732,13 +1754,13 @@ function valueAtFraction(distances, values, t) {
1732
1754
  * index `j * stride`. Fewer than three vertices or two samples leave the spine
1733
1755
  * as authored, with a stride of 1.
1734
1756
  */
1735
- function curveSpine(authored, samples) {
1757
+ function curveSpine(authored, samples, endDirection) {
1736
1758
  if (authored.length < 3 || samples < 2) return {
1737
1759
  spine: authored,
1738
1760
  stride: 1
1739
1761
  };
1740
1762
  return {
1741
- spine: catmullRom(authored, samples),
1763
+ spine: catmullRom(authored, samples, endDirection),
1742
1764
  stride: samples
1743
1765
  };
1744
1766
  }
@@ -2167,7 +2189,7 @@ function calculateSymbolGeometry(ptTip, ptWidth, spine, shaftRatio, rearWidthRat
2167
2189
  ];
2168
2190
  const fullSpine = [...remainingSpine, shaftEndCenter];
2169
2191
  const rearHalfWidth = headHalfWidth * rearWidthRatio;
2170
- const { spine: drawnSpine, stride } = smoothing === "curve" ? curveSpine(fullSpine, normalizeSmoothResolution$1(smoothResolution * CURVE_SAMPLES_PER_RESOLUTION, 5 * CURVE_SAMPLES_PER_RESOLUTION)) : {
2192
+ const { spine: drawnSpine, stride } = smoothing === "curve" ? curveSpine(fullSpine, normalizeSmoothResolution$1(smoothResolution * CURVE_SAMPLES_PER_RESOLUTION, 5 * CURVE_SAMPLES_PER_RESOLUTION), tipDir) : {
2171
2193
  spine: fullSpine,
2172
2194
  stride: 1
2173
2195
  };
@@ -2181,6 +2203,8 @@ function calculateSymbolGeometry(ptTip, ptWidth, spine, shaftRatio, rearWidthRat
2181
2203
  rounded: smoothing !== null && !(stride > 1),
2182
2204
  roundSegments: smoothResolution
2183
2205
  });
2206
+ shaftLeft[shaftLeft.length - 1] = innerLeft;
2207
+ shaftRight[shaftRight.length - 1] = innerRight;
2184
2208
  return {
2185
2209
  shaftCenterline: drawnSpine,
2186
2210
  shaftLeft,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orbat-mapper/control-measures",
3
- "version": "0.29.0",
3
+ "version": "0.29.1",
4
4
  "description": "Library for drawing tactical graphics and control measures according to MIL-STD-2525 and APP-6 standards.",
5
5
  "license": "MIT",
6
6
  "author": "Orbat Mapper",