@orbat-mapper/control-measures 0.3.1 → 0.5.0

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.
@@ -80,6 +80,8 @@ const unproject = (x, y) => {
80
80
  lat = 180 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
81
81
  return [roundToFixed(lon), roundToFixed(lat)];
82
82
  };
83
+ /** Unprojects a point in Web Mercator meters back to a GeoJSON position. */
84
+ const toPosition = (point) => unproject(point[0], point[1]);
83
85
  /**
84
86
  * Great-circle distance in meters between two lon/lat positions (haversine on
85
87
  * the WGS84 mean-radius sphere). Accurate at all scales — use this for
@@ -671,6 +673,22 @@ const pointDrawRule = {
671
673
  }
672
674
  };
673
675
  //#endregion
676
+ //#region src/draw-rules/point2.ts
677
+ /**
678
+ * Point2 — a static point symbol whose center is defined by one anchor point.
679
+ * The symbol's size and shape are carried by its options rather than additional
680
+ * control points, so moving the sole anchor translates the complete symbol.
681
+ *
682
+ * Mechanically identical to Point1: it derives from the same single-anchor
683
+ * behaviour and only re-labels it, because a definition's `rule.id` must carry
684
+ * its `metadata.drawRule` as a prefix (see the registry invariant in
685
+ * `__tests__/metadata-registry.spec.ts`, ADR-0013).
686
+ */
687
+ const staticPointDrawRule = {
688
+ ...pointDrawRule,
689
+ id: "point2:static-anchor"
690
+ };
691
+ //#endregion
674
692
  //#region src/draw-rules/area7.ts
675
693
  /**
676
694
  * Area7 anchor draw rule for Attack By Fire.
@@ -1428,6 +1446,7 @@ const AREA_SMOOTH_PARAMS = [{
1428
1446
  type: "boolean"
1429
1447
  }, {
1430
1448
  key: "smoothResolution",
1449
+ presentationTier: "advanced",
1431
1450
  label: "Smooth resolution",
1432
1451
  description: "Number of samples per segment when smooth mode is enabled.",
1433
1452
  type: "number",
@@ -1439,6 +1458,7 @@ const AREA_SMOOTH_PARAMS = [{
1439
1458
  const ATTACK_SHAFT_PARAMS = [
1440
1459
  {
1441
1460
  key: "shaftWidthRatio",
1461
+ presentationTier: "advanced",
1442
1462
  label: "Shaft width",
1443
1463
  description: "Arrow shaft width as a ratio of the arrowhead width",
1444
1464
  type: "number",
@@ -1454,6 +1474,7 @@ const ATTACK_SHAFT_PARAMS = [
1454
1474
  },
1455
1475
  {
1456
1476
  key: "smoothResolution",
1477
+ presentationTier: "advanced",
1457
1478
  label: "Smooth resolution",
1458
1479
  description: "Number of segments approximating each rounded bend when smooth mode is enabled.",
1459
1480
  type: "number",
@@ -1466,6 +1487,7 @@ const ATTACK_SHAFT_PARAMS = [
1466
1487
  const FIRE_ARROW_PARAMS = [
1467
1488
  {
1468
1489
  key: "arrowheadWidthRatio",
1490
+ presentationTier: "advanced",
1469
1491
  label: "Arrowhead width",
1470
1492
  description: "Arrowhead width as a ratio of the shaft length",
1471
1493
  type: "number",
@@ -1475,6 +1497,7 @@ const FIRE_ARROW_PARAMS = [
1475
1497
  },
1476
1498
  {
1477
1499
  key: "rearLineLengthRatio",
1500
+ presentationTier: "advanced",
1478
1501
  label: "Rear line length",
1479
1502
  description: "Length of the rear flare lines as a ratio of the head",
1480
1503
  type: "number",
@@ -1484,6 +1507,7 @@ const FIRE_ARROW_PARAMS = [
1484
1507
  },
1485
1508
  {
1486
1509
  key: "rearLineAngle",
1510
+ presentationTier: "advanced",
1487
1511
  label: "Rear line angle",
1488
1512
  description: "Angle of the rear flare lines, in degrees",
1489
1513
  type: "number",
@@ -1520,6 +1544,7 @@ const ENCIRCLEMENT_PARAMS = [
1520
1544
  },
1521
1545
  {
1522
1546
  key: "smoothResolution",
1547
+ presentationTier: "advanced",
1523
1548
  label: "Smooth resolution",
1524
1549
  description: "Number of samples per segment when smooth mode is enabled.",
1525
1550
  type: "number",
@@ -1530,6 +1555,7 @@ const ENCIRCLEMENT_PARAMS = [
1530
1555
  },
1531
1556
  {
1532
1557
  key: "barbSpacingRatio",
1558
+ presentationTier: "advanced",
1533
1559
  label: "Spacing",
1534
1560
  description: "Spacing between barbs as a ratio of the symbol radius (smaller is denser).",
1535
1561
  type: "number",
@@ -1539,6 +1565,7 @@ const ENCIRCLEMENT_PARAMS = [
1539
1565
  },
1540
1566
  {
1541
1567
  key: "barbLengthRatio",
1568
+ presentationTier: "advanced",
1542
1569
  label: "Barb length",
1543
1570
  description: "Barb height as a ratio of the symbol radius (amplitude).",
1544
1571
  type: "number",
@@ -1550,6 +1577,7 @@ const ENCIRCLEMENT_PARAMS = [
1550
1577
  const FORTIFIED_AREA_PARAMS = [...AREA_SMOOTH_PARAMS, ...FORTIFIED_AREA_SIZE_PARAMS];
1551
1578
  const AREA_LABEL_PADDING_PARAM = {
1552
1579
  key: "labelPadding",
1580
+ presentationTier: "advanced",
1553
1581
  label: "Label padding",
1554
1582
  description: "Extra spacing between the area's label rows, as a ratio of the label height",
1555
1583
  type: "number",
@@ -1565,6 +1593,8 @@ const ECHELON_AREA_PARAMS = [
1565
1593
  label: "Echelon",
1566
1594
  description: "Field B unit-size amplifier, drawn on the boundary.",
1567
1595
  type: "enum",
1596
+ presentationTier: "primary",
1597
+ semanticRole: "doctrinal",
1568
1598
  options: ECHELON_PARAM_OPTIONS
1569
1599
  },
1570
1600
  {
@@ -1589,6 +1619,7 @@ const ECHELON_AREA_PARAMS = [
1589
1619
  },
1590
1620
  {
1591
1621
  key: "echelonPadding",
1622
+ presentationTier: "advanced",
1592
1623
  label: "Echelon padding",
1593
1624
  description: "Gap on each side of the echelon, as a ratio of its height.",
1594
1625
  type: "number",
@@ -1598,6 +1629,7 @@ const ECHELON_AREA_PARAMS = [
1598
1629
  },
1599
1630
  {
1600
1631
  key: "echelonPosition",
1632
+ presentationTier: "advanced",
1601
1633
  label: "Echelon position",
1602
1634
  description: "Slide the echelon along the boundary, as a fraction of the perimeter from the bottom edge.",
1603
1635
  type: "number",
@@ -1786,6 +1818,7 @@ const AMBUSH_METADATA = {
1786
1818
  params: [
1787
1819
  {
1788
1820
  key: "arrowheadLengthRatio",
1821
+ presentationTier: "advanced",
1789
1822
  label: "Arrowhead length",
1790
1823
  description: "Arrowhead length as a ratio of the chord span",
1791
1824
  type: "number",
@@ -1795,6 +1828,7 @@ const AMBUSH_METADATA = {
1795
1828
  },
1796
1829
  {
1797
1830
  key: "arrowheadWidthRatio",
1831
+ presentationTier: "advanced",
1798
1832
  label: "Arrowhead width",
1799
1833
  description: "Arrowhead base width as a multiple of the arrowhead length",
1800
1834
  type: "number",
@@ -1804,6 +1838,7 @@ const AMBUSH_METADATA = {
1804
1838
  },
1805
1839
  {
1806
1840
  key: "hatchLengthRatio",
1841
+ presentationTier: "advanced",
1807
1842
  label: "Hatch length",
1808
1843
  description: "Length of the parallel hatches as a fraction of the chord span",
1809
1844
  type: "number",
@@ -1813,6 +1848,7 @@ const AMBUSH_METADATA = {
1813
1848
  },
1814
1849
  {
1815
1850
  key: "hatchCount",
1851
+ presentationTier: "advanced",
1816
1852
  label: "Hatch count",
1817
1853
  description: "Number of parallel hatches spaced along the curve",
1818
1854
  type: "number",
@@ -1822,6 +1858,7 @@ const AMBUSH_METADATA = {
1822
1858
  },
1823
1859
  {
1824
1860
  key: "curveDepthRatio",
1861
+ presentationTier: "advanced",
1825
1862
  label: "Curve depth",
1826
1863
  description: "How far the back line bends toward the tip, as a fraction of the chord span",
1827
1864
  type: "number",
@@ -1834,6 +1871,7 @@ const AMBUSH_METADATA = {
1834
1871
  label: "Arc segments",
1835
1872
  description: "Number of segments used to render the curve",
1836
1873
  type: "number",
1874
+ presentationTier: "advanced",
1837
1875
  min: 4,
1838
1876
  max: 96,
1839
1877
  step: 1
@@ -2028,6 +2066,10 @@ function normalizeRadians(angle) {
2028
2066
  if (normalized <= -Math.PI) normalized += Math.PI * 2;
2029
2067
  return normalized;
2030
2068
  }
2069
+ /** Wraps a degree value into the canonical clockwise `[0, 360)` range. */
2070
+ function normalizeDegrees(degrees) {
2071
+ return (degrees % 360 + 360) % 360;
2072
+ }
2031
2073
  /**
2032
2074
  * Flips a text rotation by π when it would otherwise read upside-down, keeping
2033
2075
  * the baseline pointing left-to-right (within ±90° of horizontal).
@@ -2088,6 +2130,7 @@ const SMOOTH_LINE_PARAMS = [{
2088
2130
  type: "boolean"
2089
2131
  }, {
2090
2132
  key: "smoothResolution",
2133
+ presentationTier: "advanced",
2091
2134
  label: "Smooth resolution",
2092
2135
  description: "Number of samples per segment when smooth mode is enabled.",
2093
2136
  type: "number",
@@ -2421,6 +2464,7 @@ const HOSTILE_LINE_AMPLIFIER = {
2421
2464
  /** Label-padding control shared by newly label-bearing Line1 graphics. */
2422
2465
  const LINE_LABEL_PADDING_PARAM = {
2423
2466
  key: "labelPadding",
2467
+ presentationTier: "advanced",
2424
2468
  label: "Label padding",
2425
2469
  description: "Extra clearance between the line and its labels, as a ratio of the label height",
2426
2470
  type: "number",
@@ -2883,6 +2927,7 @@ function createDirectionOfAttackLine(coordinates, options, textAmplifiers, confi
2883
2927
  const DIRECTION_OF_ATTACK_PARAMS = [
2884
2928
  {
2885
2929
  key: "arrowheadLengthRatio",
2930
+ presentationTier: "advanced",
2886
2931
  label: "Arrowhead length",
2887
2932
  description: "Arrowhead length as a ratio of the route's total length",
2888
2933
  type: "number",
@@ -2892,6 +2937,7 @@ const DIRECTION_OF_ATTACK_PARAMS = [
2892
2937
  },
2893
2938
  {
2894
2939
  key: "arrowheadWidthRatio",
2940
+ presentationTier: "advanced",
2895
2941
  label: "Arrowhead width",
2896
2942
  description: "Arrowhead total width as a ratio of its length",
2897
2943
  type: "number",
@@ -2901,6 +2947,7 @@ const DIRECTION_OF_ATTACK_PARAMS = [
2901
2947
  },
2902
2948
  {
2903
2949
  key: "labelPosition",
2950
+ presentationTier: "advanced",
2904
2951
  label: "Label position",
2905
2952
  description: "Position of the T/W/W1 group along the route, from tail (0) to tip (1)",
2906
2953
  type: "number",
@@ -2910,6 +2957,7 @@ const DIRECTION_OF_ATTACK_PARAMS = [
2910
2957
  },
2911
2958
  {
2912
2959
  key: "labelPadding",
2960
+ presentationTier: "advanced",
2913
2961
  label: "Label padding",
2914
2962
  description: "Extra spacing between the route and the date-time rows, in label heights",
2915
2963
  type: "number",
@@ -2984,6 +3032,7 @@ const DIRECTION_OF_ATTACK_AVIATION_METADATA = {
2984
3032
  ...SMOOTH_LINE_PARAMS,
2985
3033
  {
2986
3034
  key: "arrowheadLengthRatio",
3035
+ presentationTier: "advanced",
2987
3036
  label: "Arrowhead length",
2988
3037
  description: "Arrowhead length as a ratio of the route's total length",
2989
3038
  type: "number",
@@ -2993,6 +3042,7 @@ const DIRECTION_OF_ATTACK_AVIATION_METADATA = {
2993
3042
  },
2994
3043
  {
2995
3044
  key: "arrowheadWidthRatio",
3045
+ presentationTier: "advanced",
2996
3046
  label: "Arrowhead width",
2997
3047
  description: "Arrowhead total width as a ratio of its length",
2998
3048
  type: "number",
@@ -3002,6 +3052,7 @@ const DIRECTION_OF_ATTACK_AVIATION_METADATA = {
3002
3052
  },
3003
3053
  {
3004
3054
  key: "bowTieLengthRatio",
3055
+ presentationTier: "advanced",
3005
3056
  label: "Bow-tie length",
3006
3057
  description: "Aviation mark length as a ratio of the route's total length",
3007
3058
  type: "number",
@@ -3011,6 +3062,7 @@ const DIRECTION_OF_ATTACK_AVIATION_METADATA = {
3011
3062
  },
3012
3063
  {
3013
3064
  key: "bowTieWidthRatio",
3065
+ presentationTier: "advanced",
3014
3066
  label: "Bow-tie width",
3015
3067
  description: "Aviation mark total width as a ratio of its length",
3016
3068
  type: "number",
@@ -3020,6 +3072,7 @@ const DIRECTION_OF_ATTACK_AVIATION_METADATA = {
3020
3072
  },
3021
3073
  {
3022
3074
  key: "bowTiePosition",
3075
+ presentationTier: "advanced",
3023
3076
  label: "Bow-tie position",
3024
3077
  description: "Position of the aviation mark along the route, from tail (0) to tip (1)",
3025
3078
  type: "number",
@@ -3029,6 +3082,7 @@ const DIRECTION_OF_ATTACK_AVIATION_METADATA = {
3029
3082
  },
3030
3083
  {
3031
3084
  key: "labelPosition",
3085
+ presentationTier: "advanced",
3032
3086
  label: "Label position",
3033
3087
  description: "Position of the T/W/W1 group along the route, from tail (0) to tip (1)",
3034
3088
  type: "number",
@@ -3038,6 +3092,7 @@ const DIRECTION_OF_ATTACK_AVIATION_METADATA = {
3038
3092
  },
3039
3093
  {
3040
3094
  key: "labelPadding",
3095
+ presentationTier: "advanced",
3041
3096
  label: "Label padding",
3042
3097
  description: "Extra spacing between the route and the date-time rows, in label heights",
3043
3098
  type: "number",
@@ -3216,6 +3271,7 @@ const DIRECTION_OF_MAIN_ATTACK_METADATA = {
3216
3271
  ...DIRECTION_OF_ATTACK_PARAMS,
3217
3272
  {
3218
3273
  key: "arrowheadOutlineRatio",
3274
+ presentationTier: "advanced",
3219
3275
  label: "Arrowhead outline",
3220
3276
  description: "Outlined arrowhead thickness as a ratio of its length",
3221
3277
  type: "number",
@@ -3463,7 +3519,8 @@ const HORIZONTAL_LABEL_ROTATION = Math.PI;
3463
3519
  const ROW_PITCH_RATIO = 1.2;
3464
3520
  /** Clearance, as a ratio of the resolved label height, added on top of each
3465
3521
  * ENY marker's own half-width/half-height when carving its boundary
3466
- * knockout gap (see {@link pushAreaLabels}). */
3522
+ * knockout gap (see {@link pushHostileMarkers}). Exported so every measure
3523
+ * carving an ENY knockout tunes from one value. */
3467
3524
  const ENY_CLEARANCE_RATIO = .3;
3468
3525
  /** Where within each vertex-latitude band {@link ringLabelAnchor} probes for
3469
3526
  * interior chords — offset samples flank the midpoint so a self-intersection
@@ -3698,50 +3755,37 @@ function ringLabelAnchor(verts) {
3698
3755
  return anchor ?? centroid;
3699
3756
  }
3700
3757
  /**
3701
- * Pushes an area's L-15 text amplifier labels — centered name/H/W-W1 rows and
3702
- * west/east "ENY" edge markers — as `part: "label"` Point features (via
3703
- * {@link pushLabel}), all horizontal ({@link HORIZONTAL_LABEL_ROTATION}), and
3704
- * returns the {@link ArcGap}s (global arc length, matching the vertex walk
3705
- * {@link buildGappedLine} uses) an "ENY" marker knocks out of the boundary —
3706
- * empty unless `texts.hostile` was placed.
3707
- *
3708
- * Rows are `[name (T), additionalInformation (H), dtgStart (W), dtgEnd (W1)]`,
3709
- * filtered to non-empty text, stacked around the ring's {@link ringLabelAnchor}
3710
- * at `pitch = resolveLabelOffsetMeters(options, 1.2 + labelPadding)` (the 50m
3711
- * no-size fallback applies until a live label size is captured — see
3712
- * `capturesLabelSize` — so a transient row overlap is possible right after
3713
- * draw). Row *i* of *n* sits at `[cx, cy + ((n−1)/2 − i)·pitch]`, so the first
3714
- * row (the name) reads topmost.
3715
- *
3716
- * When `texts.hostile` is set, the ring's west/east crossings of the
3717
- * horizontal line through the anchor are found ({@link ringCrossingsAtY});
3718
- * the minimum/maximum-x crossings are the default anchors for the two "ENY"
3719
- * labels. A persisted `label:N:west` / `label:N:east` placement replaces that
3720
- * anchor. Each marker carves a masking {@link ArcGap} at the nearest point on
3721
- * the boundary only while its estimated text box touches the boundary; moving
3722
- * it away restores the line. The gap follows the label around any edge and is
3723
- * sized as the support function of its possibly rotated text box along the
3724
- * contacted edge's own direction `d` (a boundary running vertically there
3725
- * needs roughly the label's height; one running horizontally needs roughly
3726
- * its width):
3727
- * `halfExtent = 0.5 * (textWidth·|d.x| + textHeight·|d.y|) + clearance`, where
3728
- * `textHeight = resolveLabelOffsetMeters(options, 1)`,
3729
- * `textWidth = text.length * LABEL_CHAR_ASPECT_RATIO * textHeight`, and
3730
- * `clearance = (ENY_CLEARANCE_RATIO + labelPadding) * textHeight` — mirroring
3731
- * {@link placeEchelon}'s glyph-width masking gap (ADR-0023). Because the anchor
3732
- * is interior by construction there are normally two crossings; fewer (only a
3733
- * degenerate ring) skips the markers silently rather than guessing their default
3734
- * placements. On a self-intersecting ring the extreme crossings can belong to
3735
- * different lobes than the anchor's, which still reads as the area's west and
3736
- * east edges.
3737
- *
3738
- * A ring with fewer than 2 vertices is degenerate — nothing is placed.
3739
- *
3740
- * `maskBoundary` may supply a different rendered boundary to mask while
3741
- * keeping label placement anchored to `ringVerts`. This is used by Fortified
3742
- * Area, whose labels are centered against its smooth pre-teeth ring while the
3743
- * visible boundary follows a longer castellated trace.
3758
+ * Emits boundary text markers and returns the knockout gaps they carve in
3759
+ * `maskVerts` (ADR-0023). Movable markers mask only while their text box still
3760
+ * overlaps the finite contacted edge; intrinsic markers always mask. Callers
3761
+ * own marker names, anchors, rotation, clearance, placement keys, and fields.
3744
3762
  */
3763
+ function pushBoundaryMarkers(out, maskVerts, text, anchors, options, amplifierPlacements) {
3764
+ const { rotation, textHeight, clearance, sizeProps } = options;
3765
+ const textWidth = estimatedTextWidth(text, textHeight);
3766
+ const gaps = [];
3767
+ for (const anchor of anchors) {
3768
+ const labelPlacementKey = options.placementKeyPrefix ? `${options.placementKeyPrefix}:${anchor.side}` : void 0;
3769
+ const placement = resolveAmplifierPlacement(labelPlacementKey ? amplifierPlacements?.[labelPlacementKey] : void 0);
3770
+ const labelPoint = placement.position ? project(placement.position[0], placement.position[1]) : anchor.point;
3771
+ const boxRotation = placement.rotation ?? rotation;
3772
+ pushLabel(out, labelPoint, text, options.followPlacementRotation ? boxRotation : rotation, sizeProps, void 0, options.amplifierField, labelPlacementKey);
3773
+ const contact = placement.position !== void 0 || options.rescanDefaultAnchors === true || anchor.contact === void 0 ? nearestPointOnPolyline(maskVerts, labelPoint) : anchor.contact;
3774
+ if (!contact) continue;
3775
+ if (placement.position && !labelBoxIntersectsSegment(labelPoint, ...contact.edge, textWidth, textHeight, boxRotation)) continue;
3776
+ const tangentExtent = labelHalfExtent(contact.along, textWidth, textHeight, boxRotation) + clearance;
3777
+ pushWrappedGap(gaps, contact.arc - tangentExtent, contact.arc + tangentExtent, contact.totalArc);
3778
+ }
3779
+ return gaps;
3780
+ }
3781
+ /** Emits movable Field N markers using the generic boundary-marker knockout path. */
3782
+ function pushHostileMarkers(out, maskVerts, text, anchors, options, amplifierPlacements) {
3783
+ return pushBoundaryMarkers(out, maskVerts, text, anchors, {
3784
+ ...options,
3785
+ placementKeyPrefix: "label:N",
3786
+ amplifierField: "N"
3787
+ }, amplifierPlacements);
3788
+ }
3745
3789
  function pushAreaLabels(out, ringVerts, texts, options = {}, amplifierPlacements, maskBoundary) {
3746
3790
  if (ringVerts.length < 2) return [];
3747
3791
  const sizeProps = labelSizeProps(options);
@@ -3763,36 +3807,29 @@ function pushAreaLabels(out, ringVerts, texts, options = {}, amplifierPlacements
3763
3807
  pushLabel(out, [cx, cy + ((rows.length - 1) / 2 - i) * pitch], text, HORIZONTAL_LABEL_ROTATION, sizeProps, void 0, field);
3764
3808
  });
3765
3809
  }
3766
- const gaps = [];
3767
- if (texts.hostile) {
3768
- const { crossings, totalArc } = ringCrossingsAtY(ringVerts, cy);
3769
- if (crossings.length >= 2) {
3770
- const byX = [...crossings].sort((a, b) => a.x - b.x);
3771
- const textHeight = resolveLabelOffsetMeters(options, 1);
3772
- const textWidth = estimatedTextWidth(texts.hostile, textHeight);
3773
- const clearance = (ENY_CLEARANCE_RATIO + padding) * textHeight + Math.max(0, maskBoundary?.extraClearanceMeters ?? 0);
3774
- for (const [side, crossing] of [["west", byX[0]], ["east", byX[byX.length - 1]]]) {
3775
- const labelPlacementKey = `label:N:${side}`;
3776
- const placement = resolveAmplifierPlacement(amplifierPlacements?.[labelPlacementKey]);
3777
- const rotation = placement.rotation ?? HORIZONTAL_LABEL_ROTATION;
3778
- const labelPoint = placement.position ? project(placement.position[0], placement.position[1]) : [crossing.x, cy];
3779
- pushLabel(out, labelPoint, texts.hostile, HORIZONTAL_LABEL_ROTATION, sizeProps, void 0, "N", labelPlacementKey);
3780
- const usesDifferentMaskRing = maskRingVerts !== ringVerts;
3781
- const contact = placement.position || usesDifferentMaskRing ? nearestPointOnPolyline(maskRingVerts, labelPoint) : {
3782
- along: crossing.along,
3783
- arc: crossing.arc,
3784
- distance: 0,
3785
- totalArc,
3786
- edge: crossing.edge
3787
- };
3788
- if (!contact) continue;
3789
- if (placement.position && !labelBoxIntersectsSegment(labelPoint, ...contact.edge, textWidth, textHeight, rotation)) continue;
3790
- const tangentExtent = labelHalfExtent(contact.along, textWidth, textHeight, rotation) + clearance;
3791
- pushWrappedGap(gaps, contact.arc - tangentExtent, contact.arc + tangentExtent, contact.totalArc);
3792
- }
3793
- }
3794
- }
3795
- return gaps;
3810
+ if (!texts.hostile) return [];
3811
+ const { crossings, totalArc } = ringCrossingsAtY(ringVerts, cy);
3812
+ if (crossings.length < 2) return [];
3813
+ const byX = [...crossings].sort((a, b) => a.x - b.x);
3814
+ const anchors = [["west", byX[0]], ["east", byX[byX.length - 1]]].map(([side, crossing]) => ({
3815
+ side,
3816
+ point: [crossing.x, cy],
3817
+ contact: {
3818
+ along: crossing.along,
3819
+ arc: crossing.arc,
3820
+ distance: 0,
3821
+ totalArc,
3822
+ edge: crossing.edge
3823
+ }
3824
+ }));
3825
+ const textHeight = resolveLabelOffsetMeters(options, 1);
3826
+ return pushHostileMarkers(out, maskRingVerts, texts.hostile, anchors, {
3827
+ rotation: HORIZONTAL_LABEL_ROTATION,
3828
+ textHeight,
3829
+ clearance: (ENY_CLEARANCE_RATIO + padding) * textHeight + Math.max(0, maskBoundary?.extraClearanceMeters ?? 0),
3830
+ sizeProps,
3831
+ rescanDefaultAnchors: maskRingVerts !== ringVerts
3832
+ }, amplifierPlacements);
3796
3833
  }
3797
3834
  /**
3798
3835
  * Boundary + fill features for a pattern-filled area (e.g. Limited Access Area,
@@ -3988,6 +4025,7 @@ const AREA_DEFENSE_METADATA = {
3988
4025
  params: [
3989
4026
  {
3990
4027
  key: "arrowOpeningAngle",
4028
+ presentationTier: "advanced",
3991
4029
  label: "Arrow opening",
3992
4030
  description: "Angular opening between the two arrow tips, in degrees",
3993
4031
  type: "number",
@@ -3997,6 +4035,7 @@ const AREA_DEFENSE_METADATA = {
3997
4035
  },
3998
4036
  {
3999
4037
  key: "labelOpeningAngle",
4038
+ presentationTier: "advanced",
4000
4039
  label: "AD opening",
4001
4040
  description: "Angular opening occupied by the AD label, in degrees",
4002
4041
  type: "number",
@@ -4006,6 +4045,7 @@ const AREA_DEFENSE_METADATA = {
4006
4045
  },
4007
4046
  {
4008
4047
  key: "barbCount",
4048
+ presentationTier: "advanced",
4009
4049
  label: "Barbs",
4010
4050
  description: "Number of filled outward barbs distributed around the defense",
4011
4051
  type: "number",
@@ -4015,6 +4055,7 @@ const AREA_DEFENSE_METADATA = {
4015
4055
  },
4016
4056
  {
4017
4057
  key: "barbLengthRatio",
4058
+ presentationTier: "advanced",
4018
4059
  label: "Barb length",
4019
4060
  description: "Barb height as a ratio of the symbol radius",
4020
4061
  type: "number",
@@ -4024,6 +4065,7 @@ const AREA_DEFENSE_METADATA = {
4024
4065
  },
4025
4066
  {
4026
4067
  key: "arrowheadLengthRatio",
4068
+ presentationTier: "advanced",
4027
4069
  label: "Arrowhead length",
4028
4070
  description: "Open-arrowhead length as a ratio of the symbol radius",
4029
4071
  type: "number",
@@ -4808,6 +4850,7 @@ const ANTITANK_DITCH_PARAMS = [
4808
4850
  },
4809
4851
  {
4810
4852
  key: "toothWidthRatio",
4853
+ presentationTier: "advanced",
4811
4854
  label: "Tooth width ratio",
4812
4855
  description: "Tooth base span as a multiple of height",
4813
4856
  type: "number",
@@ -4820,6 +4863,7 @@ const ANTITANK_DITCH_PARAMS = [
4820
4863
  ];
4821
4864
  const ANTITANK_WALL_PARAMS = [...ANTITANK_DITCH_PARAMS, {
4822
4865
  key: "toothSpacingRatio",
4866
+ presentationTier: "advanced",
4823
4867
  label: "Tooth spacing ratio",
4824
4868
  description: "Gap between teeth as a multiple of base width",
4825
4869
  type: "number",
@@ -5249,6 +5293,7 @@ const ATTACK_HELICOPTER_METADATA = {
5249
5293
  ...ATTACK_SHAFT_PARAMS,
5250
5294
  {
5251
5295
  key: "symbolHeightRatio",
5296
+ presentationTier: "advanced",
5252
5297
  label: "Symbol height",
5253
5298
  description: "Height of the helicopter symbol as a ratio of the head width.",
5254
5299
  type: "number",
@@ -5258,6 +5303,7 @@ const ATTACK_HELICOPTER_METADATA = {
5258
5303
  },
5259
5304
  {
5260
5305
  key: "triangleSizeRatio",
5306
+ presentationTier: "advanced",
5261
5307
  label: "Triangle size",
5262
5308
  description: "Size of the top triangle relative to the reference unit.",
5263
5309
  type: "number",
@@ -5267,6 +5313,7 @@ const ATTACK_HELICOPTER_METADATA = {
5267
5313
  },
5268
5314
  {
5269
5315
  key: "bottomBarWidthRatio",
5316
+ presentationTier: "advanced",
5270
5317
  label: "Bottom bar width",
5271
5318
  description: "Width of the bottom bar relative to the reference triangle.",
5272
5319
  type: "number",
@@ -5276,6 +5323,7 @@ const ATTACK_HELICOPTER_METADATA = {
5276
5323
  },
5277
5324
  {
5278
5325
  key: "bowtieWidthRatio",
5326
+ presentationTier: "advanced",
5279
5327
  label: "Bowtie width",
5280
5328
  description: "Size of the central bowtie relative to the reference triangle.",
5281
5329
  type: "number",
@@ -5675,6 +5723,7 @@ const BLOCK_ARROW_METADATA = {
5675
5723
  params: [
5676
5724
  {
5677
5725
  key: "shaftWidthRatio",
5726
+ presentationTier: "advanced",
5678
5727
  label: "Shaft width",
5679
5728
  description: "Shaft band width as a fraction of the total path length",
5680
5729
  type: "number",
@@ -5720,6 +5769,7 @@ const BLOCK_ARROW_METADATA = {
5720
5769
  },
5721
5770
  {
5722
5771
  key: "arrowheadWidthRatio",
5772
+ presentationTier: "advanced",
5723
5773
  label: "Arrowhead width",
5724
5774
  description: "Arrowhead base width as a ratio of the total path length",
5725
5775
  type: "number",
@@ -5729,6 +5779,7 @@ const BLOCK_ARROW_METADATA = {
5729
5779
  },
5730
5780
  {
5731
5781
  key: "arrowheadLengthRatio",
5782
+ presentationTier: "advanced",
5732
5783
  label: "Arrowhead length",
5733
5784
  description: "Arrowhead length as a ratio of the total path length",
5734
5785
  type: "number",
@@ -5744,6 +5795,7 @@ const BLOCK_ARROW_METADATA = {
5744
5795
  },
5745
5796
  {
5746
5797
  key: "smoothResolution",
5798
+ presentationTier: "advanced",
5747
5799
  label: "Smooth resolution",
5748
5800
  description: "Number of samples per segment when smooth mode is enabled",
5749
5801
  type: "number",
@@ -5947,6 +5999,7 @@ const BOUNDARY_METADATA = {
5947
5999
  },
5948
6000
  {
5949
6001
  key: "smoothResolution",
6002
+ presentationTier: "advanced",
5950
6003
  label: "Smooth resolution",
5951
6004
  description: "Number of samples per segment when smooth mode is enabled.",
5952
6005
  type: "number",
@@ -5957,6 +6010,8 @@ const BOUNDARY_METADATA = {
5957
6010
  },
5958
6011
  {
5959
6012
  key: "echelon",
6013
+ presentationTier: "primary",
6014
+ semanticRole: "doctrinal",
5960
6015
  label: "Echelon",
5961
6016
  description: "Field B unit-size amplifier, drawn on the line",
5962
6017
  type: "enum",
@@ -5984,6 +6039,7 @@ const BOUNDARY_METADATA = {
5984
6039
  },
5985
6040
  {
5986
6041
  key: "echelonPadding",
6042
+ presentationTier: "advanced",
5987
6043
  label: "Echelon padding",
5988
6044
  description: "Gap on each side of the echelon, as a ratio of its height",
5989
6045
  type: "number",
@@ -5993,6 +6049,7 @@ const BOUNDARY_METADATA = {
5993
6049
  },
5994
6050
  {
5995
6051
  key: "labelRepetitions",
6052
+ presentationTier: "advanced",
5996
6053
  label: "Label groups",
5997
6054
  description: "Number of label groups spaced evenly along the whole boundary",
5998
6055
  type: "number",
@@ -6002,6 +6059,7 @@ const BOUNDARY_METADATA = {
6002
6059
  },
6003
6060
  {
6004
6061
  key: "labelPosition",
6062
+ presentationTier: "advanced",
6005
6063
  label: "Label position",
6006
6064
  description: "Position of the label group along the boundary, from the first point (0) to the last (1)",
6007
6065
  type: "number",
@@ -6012,6 +6070,7 @@ const BOUNDARY_METADATA = {
6012
6070
  },
6013
6071
  {
6014
6072
  key: "labelSpacing",
6073
+ presentationTier: "advanced",
6015
6074
  label: "Label spacing",
6016
6075
  description: "Spread of label groups: 1 spreads evenly, lower clusters them toward the middle.",
6017
6076
  type: "number",
@@ -6022,6 +6081,7 @@ const BOUNDARY_METADATA = {
6022
6081
  },
6023
6082
  {
6024
6083
  key: "labelPadding",
6084
+ presentationTier: "advanced",
6025
6085
  label: "Label padding",
6026
6086
  description: "Gap between the line/echelon and the unit labels, as a ratio of the echelon height",
6027
6087
  type: "number",
@@ -6031,6 +6091,7 @@ const BOUNDARY_METADATA = {
6031
6091
  },
6032
6092
  {
6033
6093
  key: "labelOrientation",
6094
+ presentationTier: "advanced",
6034
6095
  label: "Label orientation",
6035
6096
  description: "Unit labels along the line, or per MIL-STD-2525E Figure L-10: on mostly north–south segments the label group rotates perpendicular to the line as a single row crossing it.",
6036
6097
  type: "enum",
@@ -6248,6 +6309,8 @@ const LIGHT_LINE_METADATA = {
6248
6309
  ...SMOOTH_LINE_PARAMS,
6249
6310
  {
6250
6311
  key: "phaseLineName",
6312
+ presentationTier: "primary",
6313
+ semanticRole: "doctrinal",
6251
6314
  label: "Phase line name",
6252
6315
  description: "Name the line as a phase line — rendered \"PL <name>\" beyond each end of the line.",
6253
6316
  type: "text",
@@ -6264,6 +6327,7 @@ const LIGHT_LINE_METADATA = {
6264
6327
  },
6265
6328
  {
6266
6329
  key: "labelPadding",
6330
+ presentationTier: "advanced",
6267
6331
  label: "Label padding",
6268
6332
  description: "Extra clearance between the line and its labels, as a ratio of the label height",
6269
6333
  type: "number",
@@ -6324,6 +6388,8 @@ const ENGINEER_WORK_LINE_METADATA = {
6324
6388
  ...SMOOTH_LINE_PARAMS,
6325
6389
  {
6326
6390
  key: "phaseLineName",
6391
+ presentationTier: "primary",
6392
+ semanticRole: "doctrinal",
6327
6393
  label: "Phase line name",
6328
6394
  description: "Name the line as a phase line — rendered \"PL <name>\" beyond each end of the line.",
6329
6395
  type: "text",
@@ -6340,6 +6406,7 @@ const ENGINEER_WORK_LINE_METADATA = {
6340
6406
  },
6341
6407
  {
6342
6408
  key: "labelPadding",
6409
+ presentationTier: "advanced",
6343
6410
  label: "Label padding",
6344
6411
  description: "Extra clearance between the line and its labels, as a ratio of the label height",
6345
6412
  type: "number",
@@ -6464,6 +6531,8 @@ const GENERIC_C2_LINE_METADATA = {
6464
6531
  ...SMOOTH_LINE_PARAMS,
6465
6532
  {
6466
6533
  key: "phaseLineName",
6534
+ presentationTier: "primary",
6535
+ semanticRole: "doctrinal",
6467
6536
  label: "Phase line name",
6468
6537
  description: "Name the line as a phase line — rendered \"PL <name>\" beyond each end of the line.",
6469
6538
  type: "text",
@@ -6480,6 +6549,7 @@ const GENERIC_C2_LINE_METADATA = {
6480
6549
  },
6481
6550
  {
6482
6551
  key: "labelPadding",
6552
+ presentationTier: "advanced",
6483
6553
  label: "Label padding",
6484
6554
  description: "Extra clearance between the line and its labels, as a ratio of the label height",
6485
6555
  type: "number",
@@ -6583,10 +6653,6 @@ const GENERIC_C2_LINE = defineControlMeasure({
6583
6653
  });
6584
6654
  //#endregion
6585
6655
  //#region src/generators/cm34-mission-tasks/shared.ts
6586
- /** Unprojects a point in Web Mercator meters back to a GeoJSON position. */
6587
- function toPosition(point) {
6588
- return unproject(point[0], point[1]);
6589
- }
6590
6656
  /**
6591
6657
  * Builds an open chevron arrowhead (left → tip → right) as unprojected
6592
6658
  * coordinates. The tip sits at `tip`, pointing along `dir`, with the base set
@@ -6733,6 +6799,7 @@ const BLOCK_MISSION_TASK_METADATA = {
6733
6799
  capturesLabelSize: true,
6734
6800
  params: [{
6735
6801
  key: "labelGapRatio",
6802
+ presentationTier: "advanced",
6736
6803
  label: "Label gap",
6737
6804
  description: "Size of the shaft gap holding the 'B' label, as a ratio of the front length",
6738
6805
  type: "number",
@@ -6832,6 +6899,7 @@ const BREACH_METADATA = {
6832
6899
  params: [
6833
6900
  {
6834
6901
  key: "tickLengthRatio",
6902
+ presentationTier: "advanced",
6835
6903
  label: "Tick length",
6836
6904
  description: "Length of the outward end ticks, as a ratio of the front opening width",
6837
6905
  type: "number",
@@ -6841,6 +6909,7 @@ const BREACH_METADATA = {
6841
6909
  },
6842
6910
  {
6843
6911
  key: "tickAngle",
6912
+ presentationTier: "advanced",
6844
6913
  label: "Tick angle",
6845
6914
  description: "Outward lean of the end ticks from perpendicular, in degrees",
6846
6915
  type: "number",
@@ -6850,6 +6919,7 @@ const BREACH_METADATA = {
6850
6919
  },
6851
6920
  {
6852
6921
  key: "labelGapRatio",
6922
+ presentationTier: "advanced",
6853
6923
  label: "Label gap",
6854
6924
  description: "Size of the rear-line gap holding the 'B' label, as a ratio of the front length",
6855
6925
  type: "number",
@@ -6932,6 +7002,7 @@ const BYPASS_METADATA = {
6932
7002
  capturesLabelSize: true,
6933
7003
  params: [{
6934
7004
  key: "arrowheadLengthRatio",
7005
+ presentationTier: "advanced",
6935
7006
  label: "Arrowhead length",
6936
7007
  description: "Arrowhead length as a ratio of the front opening width",
6937
7008
  type: "number",
@@ -6940,6 +7011,7 @@ const BYPASS_METADATA = {
6940
7011
  step: .01
6941
7012
  }, {
6942
7013
  key: "labelGapRatio",
7014
+ presentationTier: "advanced",
6943
7015
  label: "Label gap",
6944
7016
  description: "Size of the rear-line gap holding the 'B' label, as a ratio of the front length",
6945
7017
  type: "number",
@@ -7013,6 +7085,7 @@ const CANALIZE_METADATA = {
7013
7085
  params: [
7014
7086
  {
7015
7087
  key: "tickLengthRatio",
7088
+ presentationTier: "advanced",
7016
7089
  label: "Tick length",
7017
7090
  description: "Length of the inward end ticks, as a ratio of the front opening width",
7018
7091
  type: "number",
@@ -7022,6 +7095,7 @@ const CANALIZE_METADATA = {
7022
7095
  },
7023
7096
  {
7024
7097
  key: "tickAngle",
7098
+ presentationTier: "advanced",
7025
7099
  label: "Tick angle",
7026
7100
  description: "Inward lean of the end ticks from perpendicular, in degrees",
7027
7101
  type: "number",
@@ -7031,6 +7105,7 @@ const CANALIZE_METADATA = {
7031
7105
  },
7032
7106
  {
7033
7107
  key: "labelGapRatio",
7108
+ presentationTier: "advanced",
7034
7109
  label: "Label gap",
7035
7110
  description: "Size of the rear-line gap holding the 'C' label, as a ratio of the front length",
7036
7111
  type: "number",
@@ -7121,6 +7196,7 @@ const CLASSIC_ARROW_METADATA = {
7121
7196
  },
7122
7197
  {
7123
7198
  key: "smoothResolution",
7199
+ presentationTier: "advanced",
7124
7200
  label: "Smooth resolution",
7125
7201
  description: "Number of samples per segment when smooth mode is enabled",
7126
7202
  type: "number",
@@ -7179,6 +7255,7 @@ const CLASSIC_ARROW_METADATA = {
7179
7255
  },
7180
7256
  {
7181
7257
  key: "arrowheadLengthRatio",
7258
+ presentationTier: "advanced",
7182
7259
  label: "Arrowhead length",
7183
7260
  description: "Arrowhead length as a ratio of the total path length",
7184
7261
  type: "number",
@@ -7188,6 +7265,7 @@ const CLASSIC_ARROW_METADATA = {
7188
7265
  },
7189
7266
  {
7190
7267
  key: "arrowheadWidthRatio",
7268
+ presentationTier: "advanced",
7191
7269
  label: "Arrowhead width",
7192
7270
  description: "Arrowhead base width as a ratio of the total path length",
7193
7271
  type: "number",
@@ -7396,6 +7474,7 @@ const SMOOTH_PATH_PARAMS = [{
7396
7474
  type: "boolean"
7397
7475
  }, {
7398
7476
  key: "smoothResolution",
7477
+ presentationTier: "advanced",
7399
7478
  label: "Smooth resolution",
7400
7479
  description: "Number of samples per segment when smooth mode is enabled.",
7401
7480
  type: "number",
@@ -7412,7 +7491,7 @@ const FILLED_AREA_PARAMS = [{
7412
7491
  }];
7413
7492
  //#endregion
7414
7493
  //#region src/generators/cm99-generic-graphics/circle.ts
7415
- const CIRCLE_SEGMENTS = 64;
7494
+ const CIRCLE_SEGMENTS$1 = 64;
7416
7495
  const MAX_SEGMENT_ANGLE = 6;
7417
7496
  const MAX_SUBDIVISION_DEPTH = 5;
7418
7497
  /**
@@ -7471,8 +7550,8 @@ function createGenericCircle(coordinates, options = {}) {
7471
7550
  const ring = [];
7472
7551
  let previousBearing = startBearing;
7473
7552
  let previousPoint = destinationPoint(center, radius, previousBearing);
7474
- for (let index = 1; index <= CIRCLE_SEGMENTS; index++) {
7475
- const bearing = startBearing - index / CIRCLE_SEGMENTS * 2 * Math.PI;
7553
+ for (let index = 1; index <= CIRCLE_SEGMENTS$1; index++) {
7554
+ const bearing = startBearing - index / CIRCLE_SEGMENTS$1 * 2 * Math.PI;
7476
7555
  const point = destinationPoint(center, radius, bearing);
7477
7556
  densifySegment(center, radius, previousBearing, previousPoint, bearing, point, 0, ring);
7478
7557
  previousBearing = bearing;
@@ -7722,10 +7801,6 @@ const GENERIC_RECTANGLE = defineControlMeasure({
7722
7801
  });
7723
7802
  //#endregion
7724
7803
  //#region src/generators/cm99-generic-graphics/text.ts
7725
- /** Wrap a degree value into the canonical clockwise `[0, 360)` range. */
7726
- function normalizeDegrees(degrees) {
7727
- return (degrees % 360 + 360) % 360;
7728
- }
7729
7804
  const DEFAULT_GENERIC_TEXT_OPTIONS = {
7730
7805
  text: "Text",
7731
7806
  textAlign: "center",
@@ -7759,7 +7834,9 @@ const GENERIC_TEXT_METADATA = {
7759
7834
  description: "The text to render. Explicit line breaks are honored; it never auto-wraps.",
7760
7835
  type: "text",
7761
7836
  placeholder: "Text",
7762
- multiline: true
7837
+ multiline: true,
7838
+ presentationTier: "primary",
7839
+ semanticRole: "content"
7763
7840
  },
7764
7841
  {
7765
7842
  key: "textAlign",
@@ -7929,6 +8006,7 @@ const CLEAR_METADATA = {
7929
8006
  params: [
7930
8007
  {
7931
8008
  key: "arrowInsetRatio",
8009
+ presentationTier: "advanced",
7932
8010
  label: "Arrow padding",
7933
8011
  description: "Padding between the line endpoints and the outer arrows, as a ratio of height",
7934
8012
  type: "number",
@@ -7938,6 +8016,7 @@ const CLEAR_METADATA = {
7938
8016
  },
7939
8017
  {
7940
8018
  key: "arrowheadLengthRatio",
8019
+ presentationTier: "advanced",
7941
8020
  label: "Arrowhead length",
7942
8021
  description: "Arrowhead length as a ratio of the symbol height",
7943
8022
  type: "number",
@@ -7947,6 +8026,7 @@ const CLEAR_METADATA = {
7947
8026
  },
7948
8027
  {
7949
8028
  key: "arrowheadWidthRatio",
8029
+ presentationTier: "advanced",
7950
8030
  label: "Arrowhead width",
7951
8031
  description: "Arrowhead base width as a ratio of the symbol height",
7952
8032
  type: "number",
@@ -7956,6 +8036,7 @@ const CLEAR_METADATA = {
7956
8036
  },
7957
8037
  {
7958
8038
  key: "labelGapRatio",
8039
+ presentationTier: "advanced",
7959
8040
  label: "Label gap",
7960
8041
  description: "Size of the shaft gap holding the 'C' label, as a ratio of the shaft length",
7961
8042
  type: "number",
@@ -8162,6 +8243,7 @@ const COUNTERATTACK_METADATA = {
8162
8243
  capturesLabelSize: true,
8163
8244
  params: [...ATTACK_SHAFT_PARAMS, {
8164
8245
  key: "labelPosition",
8246
+ presentationTier: "advanced",
8165
8247
  label: "Label position",
8166
8248
  description: "Position of the CATK label along the shaft, from tail (0) to head (1)",
8167
8249
  type: "number",
@@ -8281,6 +8363,7 @@ const COUNTERATTACK_BY_FIRE_METADATA = {
8281
8363
  capturesLabelSize: true,
8282
8364
  params: [...ATTACK_SHAFT_PARAMS, {
8283
8365
  key: "labelPosition",
8366
+ presentationTier: "advanced",
8284
8367
  label: "Label position",
8285
8368
  description: "Position of the CATK label along the shaft, from tail (0) to head (1)",
8286
8369
  type: "number",
@@ -8496,6 +8579,7 @@ const SEARCH_AREA_METADATA = {
8496
8579
  params: [
8497
8580
  {
8498
8581
  key: "arrowheadLengthRatio",
8582
+ presentationTier: "advanced",
8499
8583
  label: "Arrowhead length",
8500
8584
  description: "Arrowhead length as a ratio of the total leg length",
8501
8585
  type: "number",
@@ -8505,6 +8589,7 @@ const SEARCH_AREA_METADATA = {
8505
8589
  },
8506
8590
  {
8507
8591
  key: "arrowheadWidthRatio",
8592
+ presentationTier: "advanced",
8508
8593
  label: "Arrowhead width",
8509
8594
  description: "Arrowhead base width as a multiple of the arrowhead length",
8510
8595
  type: "number",
@@ -8514,6 +8599,7 @@ const SEARCH_AREA_METADATA = {
8514
8599
  },
8515
8600
  {
8516
8601
  key: "zigzagStart",
8602
+ presentationTier: "advanced",
8517
8603
  label: "Zigzag start",
8518
8604
  description: "Point along the leg where the zigzag begins (0-1).",
8519
8605
  type: "number",
@@ -8523,6 +8609,7 @@ const SEARCH_AREA_METADATA = {
8523
8609
  },
8524
8610
  {
8525
8611
  key: "zigzagEnd",
8612
+ presentationTier: "advanced",
8526
8613
  label: "Zigzag end",
8527
8614
  description: "Point along the leg where the zigzag returns (0-1).",
8528
8615
  type: "number",
@@ -8532,6 +8619,7 @@ const SEARCH_AREA_METADATA = {
8532
8619
  },
8533
8620
  {
8534
8621
  key: "zigzagAmplitudeRatio",
8622
+ presentationTier: "advanced",
8535
8623
  label: "Zigzag amplitude",
8536
8624
  description: "Perpendicular kink offset as a ratio of leg length.",
8537
8625
  type: "number",
@@ -8641,6 +8729,7 @@ const DEFAULT_SECURITY_TASK_OPTIONS = {
8641
8729
  const SECURITY_TASK_PARAMS = [
8642
8730
  {
8643
8731
  key: "arrowheadLengthRatio",
8732
+ presentationTier: "advanced",
8644
8733
  label: "Arrowhead length",
8645
8734
  description: "Arrowhead length as a ratio of the total leg length",
8646
8735
  type: "number",
@@ -8650,6 +8739,7 @@ const SECURITY_TASK_PARAMS = [
8650
8739
  },
8651
8740
  {
8652
8741
  key: "arrowheadWidthRatio",
8742
+ presentationTier: "advanced",
8653
8743
  label: "Arrowhead width",
8654
8744
  description: "Arrowhead base width as a multiple of the arrowhead length",
8655
8745
  type: "number",
@@ -8659,6 +8749,7 @@ const SECURITY_TASK_PARAMS = [
8659
8749
  },
8660
8750
  {
8661
8751
  key: "zigzagStart",
8752
+ presentationTier: "advanced",
8662
8753
  label: "Zigzag start",
8663
8754
  description: "Point along the leg where the zigzag begins (0-1).",
8664
8755
  type: "number",
@@ -8668,6 +8759,7 @@ const SECURITY_TASK_PARAMS = [
8668
8759
  },
8669
8760
  {
8670
8761
  key: "zigzagEnd",
8762
+ presentationTier: "advanced",
8671
8763
  label: "Zigzag end",
8672
8764
  description: "Point along the leg where the zigzag returns (0-1).",
8673
8765
  type: "number",
@@ -8677,6 +8769,7 @@ const SECURITY_TASK_PARAMS = [
8677
8769
  },
8678
8770
  {
8679
8771
  key: "zigzagAmplitudeRatio",
8772
+ presentationTier: "advanced",
8680
8773
  label: "Zigzag amplitude",
8681
8774
  description: "Perpendicular kink offset as a ratio of leg length.",
8682
8775
  type: "number",
@@ -8686,6 +8779,7 @@ const SECURITY_TASK_PARAMS = [
8686
8779
  },
8687
8780
  {
8688
8781
  key: "labelInsetRatio",
8782
+ presentationTier: "advanced",
8689
8783
  label: "Letter position",
8690
8784
  description: "Inset of each task letter from PT. 2 or PT. 3 across the center opening",
8691
8785
  type: "number",
@@ -8824,6 +8918,7 @@ const DEFAULT_DELAY_OPTIONS = {
8824
8918
  const DELAY_PARAMS = [
8825
8919
  {
8826
8920
  key: "arrowheadLengthRatio",
8921
+ presentationTier: "advanced",
8827
8922
  label: "Arrowhead length",
8828
8923
  description: "Arrowhead length as a ratio of the straight-line length",
8829
8924
  type: "number",
@@ -8833,6 +8928,7 @@ const DELAY_PARAMS = [
8833
8928
  },
8834
8929
  {
8835
8930
  key: "arrowheadWidthRatio",
8931
+ presentationTier: "advanced",
8836
8932
  label: "Arrowhead width",
8837
8933
  description: "Arrowhead base width as a ratio of the straight-line length",
8838
8934
  type: "number",
@@ -8842,6 +8938,7 @@ const DELAY_PARAMS = [
8842
8938
  },
8843
8939
  {
8844
8940
  key: "labelGapRatio",
8941
+ presentationTier: "advanced",
8845
8942
  label: "Label gap",
8846
8943
  description: "Size of the shaft gap holding the task label, as a ratio of the shaft length",
8847
8944
  type: "number",
@@ -8851,6 +8948,7 @@ const DELAY_PARAMS = [
8851
8948
  },
8852
8949
  {
8853
8950
  key: "arcSegments",
8951
+ presentationTier: "advanced",
8854
8952
  label: "Arc segments",
8855
8953
  description: "Number of straight segments used to approximate the semicircular arc",
8856
8954
  type: "number",
@@ -9038,6 +9136,7 @@ const DISRUPT_MISSION_TASK_METADATA = {
9038
9136
  params: [
9039
9137
  {
9040
9138
  key: "middleArrowLengthRatio",
9139
+ presentationTier: "advanced",
9041
9140
  label: "Middle arrow length",
9042
9141
  description: "Middle arrow length as a ratio of the PT.3-controlled top arrow",
9043
9142
  type: "number",
@@ -9047,6 +9146,7 @@ const DISRUPT_MISSION_TASK_METADATA = {
9047
9146
  },
9048
9147
  {
9049
9148
  key: "bottomArrowLengthRatio",
9149
+ presentationTier: "advanced",
9050
9150
  label: "Bottom arrow length",
9051
9151
  description: "Bottom arrow length as a ratio of the PT.3-controlled top arrow",
9052
9152
  type: "number",
@@ -9056,6 +9156,7 @@ const DISRUPT_MISSION_TASK_METADATA = {
9056
9156
  },
9057
9157
  {
9058
9158
  key: "shaftLengthRatio",
9159
+ presentationTier: "advanced",
9059
9160
  label: "Rear shaft length",
9060
9161
  description: "Middle shaft extension behind the spine, as a ratio of the top arrow",
9061
9162
  type: "number",
@@ -9065,6 +9166,7 @@ const DISRUPT_MISSION_TASK_METADATA = {
9065
9166
  },
9066
9167
  {
9067
9168
  key: "arrowheadLengthRatio",
9169
+ presentationTier: "advanced",
9068
9170
  label: "Arrowhead length",
9069
9171
  description: "Arrowhead length as a ratio of the spine length",
9070
9172
  type: "number",
@@ -9074,6 +9176,7 @@ const DISRUPT_MISSION_TASK_METADATA = {
9074
9176
  },
9075
9177
  {
9076
9178
  key: "arrowheadWidthRatio",
9179
+ presentationTier: "advanced",
9077
9180
  label: "Arrowhead width",
9078
9181
  description: "Arrowhead base width as a ratio of the spine length",
9079
9182
  type: "number",
@@ -9083,6 +9186,7 @@ const DISRUPT_MISSION_TASK_METADATA = {
9083
9186
  },
9084
9187
  {
9085
9188
  key: "labelGapRatio",
9189
+ presentationTier: "advanced",
9086
9190
  label: "Label gap",
9087
9191
  description: "Size of the middle-shaft gap holding the 'D' label",
9088
9192
  type: "number",
@@ -9236,6 +9340,7 @@ const DISRUPT_METADATA = {
9236
9340
  params: [
9237
9341
  {
9238
9342
  key: "middleArrowLengthRatio",
9343
+ presentationTier: "advanced",
9239
9344
  label: "Middle arrow length",
9240
9345
  description: "Middle arrow length as a ratio of the longest (top) arrow.",
9241
9346
  type: "number",
@@ -9245,6 +9350,7 @@ const DISRUPT_METADATA = {
9245
9350
  },
9246
9351
  {
9247
9352
  key: "bottomArrowLengthRatio",
9353
+ presentationTier: "advanced",
9248
9354
  label: "Bottom arrow length",
9249
9355
  description: "Bottom arrow length as a ratio of the longest (top) arrow.",
9250
9356
  type: "number",
@@ -9254,6 +9360,7 @@ const DISRUPT_METADATA = {
9254
9360
  },
9255
9361
  {
9256
9362
  key: "shaftLengthRatio",
9363
+ presentationTier: "advanced",
9257
9364
  label: "Shaft length",
9258
9365
  description: "Center shaft length as a ratio of the longest arrow, extending opposite.",
9259
9366
  type: "number",
@@ -9263,6 +9370,7 @@ const DISRUPT_METADATA = {
9263
9370
  },
9264
9371
  {
9265
9372
  key: "arrowheadLengthRatio",
9373
+ presentationTier: "advanced",
9266
9374
  label: "Arrowhead length",
9267
9375
  description: "Arrowhead length as a ratio of the longest arrow",
9268
9376
  type: "number",
@@ -9272,6 +9380,7 @@ const DISRUPT_METADATA = {
9272
9380
  },
9273
9381
  {
9274
9382
  key: "arrowheadWidthRatio",
9383
+ presentationTier: "advanced",
9275
9384
  label: "Arrowhead width",
9276
9385
  description: "Arrowhead base width as a ratio of the longest arrow",
9277
9386
  type: "number",
@@ -9695,6 +9804,7 @@ const FPF_SHARED = {
9695
9804
  params: [
9696
9805
  {
9697
9806
  key: "arrowheadLengthRatio",
9807
+ presentationTier: "advanced",
9698
9808
  label: "Arrowhead length",
9699
9809
  description: "Arrowhead length as a ratio of each arm's length",
9700
9810
  type: "number",
@@ -9704,6 +9814,7 @@ const FPF_SHARED = {
9704
9814
  },
9705
9815
  {
9706
9816
  key: "arrowheadWidthRatio",
9817
+ presentationTier: "advanced",
9707
9818
  label: "Arrowhead width",
9708
9819
  description: "Arrowhead base width as a multiple of the arrowhead length",
9709
9820
  type: "number",
@@ -9713,6 +9824,7 @@ const FPF_SHARED = {
9713
9824
  },
9714
9825
  {
9715
9826
  key: "bladeHeightRatio",
9827
+ presentationTier: "advanced",
9716
9828
  label: "Blade height",
9717
9829
  description: "Blade's perpendicular reach into the V, as a fraction of its arm's length",
9718
9830
  type: "number",
@@ -9883,6 +9995,7 @@ const FIX_METADATA = {
9883
9995
  params: [
9884
9996
  {
9885
9997
  key: "arrowheadAngle",
9998
+ presentationTier: "advanced",
9886
9999
  label: "Arrowhead angle",
9887
10000
  description: "Half-angle of the open arrowhead wings, in degrees.",
9888
10001
  type: "number",
@@ -9892,6 +10005,7 @@ const FIX_METADATA = {
9892
10005
  },
9893
10006
  {
9894
10007
  key: "arrowheadLengthRatio",
10008
+ presentationTier: "advanced",
9895
10009
  label: "Arrowhead length",
9896
10010
  description: "Arrowhead length as a ratio of the axis length",
9897
10011
  type: "number",
@@ -9901,6 +10015,7 @@ const FIX_METADATA = {
9901
10015
  },
9902
10016
  {
9903
10017
  key: "endSegmentRatio",
10018
+ presentationTier: "advanced",
9904
10019
  label: "End segment",
9905
10020
  description: "Flat end segment length as a ratio of the axis (capped at 0.35).",
9906
10021
  type: "number",
@@ -10025,6 +10140,7 @@ const FIX_MISSION_TASK_METADATA = {
10025
10140
  params: [
10026
10141
  {
10027
10142
  key: "arrowheadLengthRatio",
10143
+ presentationTier: "advanced",
10028
10144
  label: "Arrowhead length",
10029
10145
  description: "Arrowhead length as a ratio of the axis length",
10030
10146
  type: "number",
@@ -10034,6 +10150,7 @@ const FIX_MISSION_TASK_METADATA = {
10034
10150
  },
10035
10151
  {
10036
10152
  key: "arrowheadWidthRatio",
10153
+ presentationTier: "advanced",
10037
10154
  label: "Arrowhead width",
10038
10155
  description: "Arrowhead base width as a ratio of the axis length",
10039
10156
  type: "number",
@@ -10043,6 +10160,7 @@ const FIX_MISSION_TASK_METADATA = {
10043
10160
  },
10044
10161
  {
10045
10162
  key: "zigzagStartRatio",
10163
+ presentationTier: "advanced",
10046
10164
  label: "Zigzag start",
10047
10165
  description: "Position where the zigzag begins, measured from PT2",
10048
10166
  type: "number",
@@ -10052,6 +10170,7 @@ const FIX_MISSION_TASK_METADATA = {
10052
10170
  },
10053
10171
  {
10054
10172
  key: "zigzagEndRatio",
10173
+ presentationTier: "advanced",
10055
10174
  label: "Zigzag end",
10056
10175
  description: "Position where the zigzag ends, measured from PT2",
10057
10176
  type: "number",
@@ -10061,6 +10180,7 @@ const FIX_MISSION_TASK_METADATA = {
10061
10180
  },
10062
10181
  {
10063
10182
  key: "zigzagPeakCount",
10183
+ presentationTier: "advanced",
10064
10184
  label: "Zigzag peaks",
10065
10185
  description: "Number of upward peaks in the zigzag body",
10066
10186
  type: "number",
@@ -10070,6 +10190,7 @@ const FIX_MISSION_TASK_METADATA = {
10070
10190
  },
10071
10191
  {
10072
10192
  key: "labelPositionRatio",
10193
+ presentationTier: "advanced",
10073
10194
  label: "Label position",
10074
10195
  description: "Position of the F label along the axis, measured from PT2",
10075
10196
  type: "number",
@@ -10079,6 +10200,7 @@ const FIX_MISSION_TASK_METADATA = {
10079
10200
  },
10080
10201
  {
10081
10202
  key: "labelGapRatio",
10203
+ presentationTier: "advanced",
10082
10204
  label: "Label gap",
10083
10205
  description: "Size of the shaft gap holding the F label",
10084
10206
  type: "number",
@@ -10219,6 +10341,7 @@ const FLOT_METADATA = {
10219
10341
  LINE_LABEL_PADDING_PARAM,
10220
10342
  {
10221
10343
  key: "arcSegments",
10344
+ presentationTier: "advanced",
10222
10345
  label: "Arc segments",
10223
10346
  description: "Number of points used to render each semicircle",
10224
10347
  type: "number",
@@ -10397,6 +10520,7 @@ const PHASE_LINE_METADATA = {
10397
10520
  },
10398
10521
  {
10399
10522
  key: "labelPadding",
10523
+ presentationTier: "advanced",
10400
10524
  label: "Label padding",
10401
10525
  description: "Extra clearance between the line and its labels, as a ratio of the label height",
10402
10526
  type: "number",
@@ -10466,6 +10590,8 @@ const BRIDGEHEAD_LINE_METADATA = {
10466
10590
  ...SMOOTH_LINE_PARAMS,
10467
10591
  {
10468
10592
  key: "phaseLineName",
10593
+ presentationTier: "primary",
10594
+ semanticRole: "doctrinal",
10469
10595
  label: "Phase line name",
10470
10596
  description: "Name the line as a phase line — rendered \"PL <name>\" beyond each end of the line.",
10471
10597
  type: "text",
@@ -10482,6 +10608,7 @@ const BRIDGEHEAD_LINE_METADATA = {
10482
10608
  },
10483
10609
  {
10484
10610
  key: "labelPadding",
10611
+ presentationTier: "advanced",
10485
10612
  label: "Label padding",
10486
10613
  description: "Extra clearance between the line and its labels, as a ratio of the label height",
10487
10614
  type: "number",
@@ -10539,6 +10666,8 @@ const HOLDING_LINE_METADATA = {
10539
10666
  ...SMOOTH_LINE_PARAMS,
10540
10667
  {
10541
10668
  key: "phaseLineName",
10669
+ presentationTier: "primary",
10670
+ semanticRole: "doctrinal",
10542
10671
  label: "Phase line name",
10543
10672
  description: "Name the line as a phase line — rendered \"PL <name>\" beyond each end of the line.",
10544
10673
  type: "text",
@@ -10555,6 +10684,7 @@ const HOLDING_LINE_METADATA = {
10555
10684
  },
10556
10685
  {
10557
10686
  key: "labelPadding",
10687
+ presentationTier: "advanced",
10558
10688
  label: "Label padding",
10559
10689
  description: "Extra clearance between the line and its labels, as a ratio of the label height",
10560
10690
  type: "number",
@@ -10612,6 +10742,8 @@ const RELEASE_LINE_METADATA = {
10612
10742
  ...SMOOTH_LINE_PARAMS,
10613
10743
  {
10614
10744
  key: "phaseLineName",
10745
+ presentationTier: "primary",
10746
+ semanticRole: "doctrinal",
10615
10747
  label: "Phase line name",
10616
10748
  description: "Name the line as a phase line — rendered \"PL <name>\" beyond each end of the line.",
10617
10749
  type: "text",
@@ -10628,6 +10760,7 @@ const RELEASE_LINE_METADATA = {
10628
10760
  },
10629
10761
  {
10630
10762
  key: "labelPadding",
10763
+ presentationTier: "advanced",
10631
10764
  label: "Label padding",
10632
10765
  description: "Extra clearance between the line and its labels, as a ratio of the label height",
10633
10766
  type: "number",
@@ -10685,6 +10818,8 @@ const FORWARD_EDGE_OF_BATTLE_AREA_METADATA = {
10685
10818
  ...SMOOTH_LINE_PARAMS,
10686
10819
  {
10687
10820
  key: "phaseLineName",
10821
+ presentationTier: "primary",
10822
+ semanticRole: "doctrinal",
10688
10823
  label: "Phase line name",
10689
10824
  description: "Name the line as a phase line — rendered \"PL <name>\" beyond each end of the line.",
10690
10825
  type: "text",
@@ -10701,6 +10836,7 @@ const FORWARD_EDGE_OF_BATTLE_AREA_METADATA = {
10701
10836
  },
10702
10837
  {
10703
10838
  key: "labelPadding",
10839
+ presentationTier: "advanced",
10704
10840
  label: "Label padding",
10705
10841
  description: "Extra clearance between the line and its labels, as a ratio of the label height",
10706
10842
  type: "number",
@@ -10766,7 +10902,9 @@ const HANDOVER_LINE_METADATA = {
10766
10902
  type: "text",
10767
10903
  placeholder: "DAVID",
10768
10904
  maxLength: 21,
10769
- field: "T"
10905
+ field: "T",
10906
+ presentationTier: "primary",
10907
+ semanticRole: "doctrinal"
10770
10908
  },
10771
10909
  {
10772
10910
  key: "includePrefix",
@@ -10777,6 +10915,7 @@ const HANDOVER_LINE_METADATA = {
10777
10915
  },
10778
10916
  {
10779
10917
  key: "labelPadding",
10918
+ presentationTier: "advanced",
10780
10919
  label: "Label padding",
10781
10920
  description: "Extra clearance between the line and its labels, as a ratio of the label height",
10782
10921
  type: "number",
@@ -10837,6 +10976,8 @@ const BATTLE_HANDOVER_LINE_METADATA = {
10837
10976
  ...SMOOTH_LINE_PARAMS,
10838
10977
  {
10839
10978
  key: "phaseLineName",
10979
+ presentationTier: "primary",
10980
+ semanticRole: "doctrinal",
10840
10981
  label: "Phase line name",
10841
10982
  description: "Name the line as a phase line — rendered \"PL <name>\" beyond each end of the line.",
10842
10983
  type: "text",
@@ -10853,6 +10994,7 @@ const BATTLE_HANDOVER_LINE_METADATA = {
10853
10994
  },
10854
10995
  {
10855
10996
  key: "labelPadding",
10997
+ presentationTier: "advanced",
10856
10998
  label: "Label padding",
10857
10999
  description: "Extra clearance between the line and its labels, as a ratio of the label height",
10858
11000
  type: "number",
@@ -11238,6 +11380,7 @@ function createManeuverArrowTask(coordinates, options, textAmplifiers, config) {
11238
11380
  const MANEUVER_ARROW_TASK_PARAMS = [
11239
11381
  {
11240
11382
  key: "crossbarLengthRatio",
11383
+ presentationTier: "advanced",
11241
11384
  label: "Straight line length",
11242
11385
  description: "Crossbar length as a multiple of the arrowhead base width",
11243
11386
  type: "number",
@@ -11247,6 +11390,7 @@ const MANEUVER_ARROW_TASK_PARAMS = [
11247
11390
  },
11248
11391
  {
11249
11392
  key: "labelPosition",
11393
+ presentationTier: "advanced",
11250
11394
  label: "Designation position",
11251
11395
  description: "Position of Field T along the shaft, from tail (0) to head (1)",
11252
11396
  type: "number",
@@ -11256,6 +11400,7 @@ const MANEUVER_ARROW_TASK_PARAMS = [
11256
11400
  },
11257
11401
  {
11258
11402
  key: "dtgPosition",
11403
+ presentationTier: "advanced",
11259
11404
  label: "Date-time position",
11260
11405
  description: "Position of Fields W/W1 along the shaft, from tail (0) to head (1)",
11261
11406
  type: "number",
@@ -11265,6 +11410,7 @@ const MANEUVER_ARROW_TASK_PARAMS = [
11265
11410
  },
11266
11411
  {
11267
11412
  key: "labelPadding",
11413
+ presentationTier: "advanced",
11268
11414
  label: "Label padding",
11269
11415
  description: "Extra spacing between the W and W1 rows, in label heights",
11270
11416
  type: "number",
@@ -11374,6 +11520,7 @@ const ISOLATE_METADATA = {
11374
11520
  params: [
11375
11521
  {
11376
11522
  key: "openingAngle",
11523
+ presentationTier: "advanced",
11377
11524
  label: "Opening",
11378
11525
  description: "Angular width of the gap on the friendly side, in degrees",
11379
11526
  type: "number",
@@ -11383,6 +11530,7 @@ const ISOLATE_METADATA = {
11383
11530
  },
11384
11531
  {
11385
11532
  key: "barbCount",
11533
+ presentationTier: "advanced",
11386
11534
  label: "Barbs",
11387
11535
  description: "Number of inward-pointing barbs spaced along the closed arc",
11388
11536
  type: "number",
@@ -11392,6 +11540,7 @@ const ISOLATE_METADATA = {
11392
11540
  },
11393
11541
  {
11394
11542
  key: "barbLengthRatio",
11543
+ presentationTier: "advanced",
11395
11544
  label: "Barb length",
11396
11545
  description: "Length of each inward barb, as a ratio of the symbol radius",
11397
11546
  type: "number",
@@ -11507,6 +11656,7 @@ const PENETRATE_METADATA = {
11507
11656
  params: [
11508
11657
  {
11509
11658
  key: "arrowheadLengthRatio",
11659
+ presentationTier: "advanced",
11510
11660
  label: "Arrowhead length",
11511
11661
  description: "Arrowhead length as a ratio of the barrier length",
11512
11662
  type: "number",
@@ -11516,6 +11666,7 @@ const PENETRATE_METADATA = {
11516
11666
  },
11517
11667
  {
11518
11668
  key: "arrowheadWidthRatio",
11669
+ presentationTier: "advanced",
11519
11670
  label: "Arrowhead width",
11520
11671
  description: "Arrowhead base width as a ratio of the barrier length",
11521
11672
  type: "number",
@@ -11525,6 +11676,7 @@ const PENETRATE_METADATA = {
11525
11676
  },
11526
11677
  {
11527
11678
  key: "labelGapRatio",
11679
+ presentationTier: "advanced",
11528
11680
  label: "Label gap",
11529
11681
  description: "Size of the shaft gap holding the 'P' label",
11530
11682
  type: "number",
@@ -11748,6 +11900,7 @@ const SEIZE_METADATA = {
11748
11900
  params: [
11749
11901
  {
11750
11902
  key: "arrowheadLengthRatio",
11903
+ presentationTier: "advanced",
11751
11904
  label: "Arrowhead length",
11752
11905
  description: "Arrowhead length as a ratio of the PT. 2-to-PT. 4 span",
11753
11906
  type: "number",
@@ -11757,6 +11910,7 @@ const SEIZE_METADATA = {
11757
11910
  },
11758
11911
  {
11759
11912
  key: "arrowheadWidthRatio",
11913
+ presentationTier: "advanced",
11760
11914
  label: "Arrowhead width",
11761
11915
  description: "Arrowhead base width as a ratio of the PT. 2-to-PT. 4 span",
11762
11916
  type: "number",
@@ -11766,6 +11920,7 @@ const SEIZE_METADATA = {
11766
11920
  },
11767
11921
  {
11768
11922
  key: "labelGapRatio",
11923
+ presentationTier: "advanced",
11769
11924
  label: "Label gap",
11770
11925
  description: "Size of the curve gap holding the S label",
11771
11926
  type: "number",
@@ -11775,6 +11930,7 @@ const SEIZE_METADATA = {
11775
11930
  },
11776
11931
  {
11777
11932
  key: "curveSegments",
11933
+ presentationTier: "advanced",
11778
11934
  label: "Curve segments",
11779
11935
  description: "Number of straight segments used to approximate the circular arc",
11780
11936
  type: "number",
@@ -11784,6 +11940,7 @@ const SEIZE_METADATA = {
11784
11940
  },
11785
11941
  {
11786
11942
  key: "circleSegments",
11943
+ presentationTier: "advanced",
11787
11944
  label: "Circle segments",
11788
11945
  description: "Number of straight segments used to approximate the assigned-unit circle",
11789
11946
  type: "number",
@@ -12374,10 +12531,445 @@ const MAIN_ATTACK = defineControlMeasure({
12374
12531
  rule: axis1DrawRule
12375
12532
  });
12376
12533
  //#endregion
12534
+ //#region src/generators/cm27-protection-areas/mine-types.ts
12535
+ /** Shared Modifier 1 parameter used by all minefield and mined-area graphics. */
12536
+ const MINE_TYPE_PARAM = {
12537
+ key: "mineType",
12538
+ label: "Mine type",
12539
+ description: "Modifier 1 (symbol set 25 values 13–18).",
12540
+ type: "enum",
12541
+ presentationTier: "primary",
12542
+ semanticRole: "doctrinal",
12543
+ options: [
12544
+ {
12545
+ label: "Unspecified mine (13)",
12546
+ value: "unspecified"
12547
+ },
12548
+ {
12549
+ label: "Antipersonnel mine (14)",
12550
+ value: "antipersonnel"
12551
+ },
12552
+ {
12553
+ label: "Antipersonnel mine with directional effects (15)",
12554
+ value: "antipersonnel-directional"
12555
+ },
12556
+ {
12557
+ label: "Antitank mine (16)",
12558
+ value: "antitank"
12559
+ },
12560
+ {
12561
+ label: "Antitank mine with antihandling device (17)",
12562
+ value: "antitank-antihandling"
12563
+ },
12564
+ {
12565
+ label: "Wide area antitank mine (18)",
12566
+ value: "wide-area-antitank"
12567
+ }
12568
+ ]
12569
+ };
12570
+ const MINE_FILL_PATTERNS = {
12571
+ unspecified: "mine-unspecified",
12572
+ antipersonnel: "mine-antipersonnel",
12573
+ "antipersonnel-directional": "mine-antipersonnel-directional",
12574
+ antitank: "mine-antitank",
12575
+ "antitank-antihandling": "mine-antitank-antihandling",
12576
+ "wide-area-antitank": "mine-wide-area-antitank"
12577
+ };
12578
+ function mineFillPattern(mineType) {
12579
+ return MINE_FILL_PATTERNS[mineType];
12580
+ }
12581
+ //#endregion
12582
+ //#region src/generators/cm27-protection-areas/minefield.ts
12583
+ const DEFAULT_MINEFIELD_OPTIONS = {
12584
+ mineType: "unspecified",
12585
+ sizePixels: 32,
12586
+ rotation: 0
12587
+ };
12588
+ /** Pure-render fallback when a pixel default is used without adapter resolution. */
12589
+ const DEFAULT_MINEFIELD_SIZE_METERS = 1e3;
12590
+ const MINEFIELD_METADATA = {
12591
+ id: "minefield",
12592
+ name: "Minefield",
12593
+ description: "A static point symbol identifying a minefield and its mine type.",
12594
+ entity: "Protection Areas",
12595
+ entityType: "Minefield Symbol",
12596
+ entitySubtype: "Minefield (Static)",
12597
+ value: "270701",
12598
+ minCoordinates: 1,
12599
+ maxCoordinates: 1,
12600
+ geometry: "point",
12601
+ geometryTypes: [
12602
+ "LineString",
12603
+ "MultiLineString",
12604
+ "MultiPolygon",
12605
+ "Point"
12606
+ ],
12607
+ paints: {
12608
+ stroke: true,
12609
+ fill: "fixed",
12610
+ text: true
12611
+ },
12612
+ drawRule: "Point2",
12613
+ params: [
12614
+ MINE_TYPE_PARAM,
12615
+ {
12616
+ key: "sizeMeters",
12617
+ label: "Size",
12618
+ description: "Overall width of the static symbol.",
12619
+ type: "number",
12620
+ min: 10,
12621
+ max: 1e5,
12622
+ step: 10,
12623
+ unit: "m"
12624
+ },
12625
+ {
12626
+ key: "rotation",
12627
+ label: "Rotation",
12628
+ description: "Clockwise rotation of the static symbol.",
12629
+ type: "number",
12630
+ min: 0,
12631
+ max: 360,
12632
+ step: 1,
12633
+ unit: "°"
12634
+ }
12635
+ ],
12636
+ textAmplifiers: [
12637
+ {
12638
+ ...AREA_HOSTILE_AMPLIFIER,
12639
+ description: "Field N — literal \"ENY\" marker at the minefield's west and east sides."
12640
+ },
12641
+ {
12642
+ key: "H",
12643
+ label: "Additional information",
12644
+ description: "Field H — additional information shown above the minefield.",
12645
+ placeholder: "+S",
12646
+ maxLength: 20
12647
+ },
12648
+ {
12649
+ key: "W",
12650
+ label: "Date-time group",
12651
+ description: "Field W — date-time group shown below the minefield.",
12652
+ placeholder: "032400ZJUL2007",
12653
+ maxLength: 16
12654
+ }
12655
+ ]
12656
+ };
12657
+ const CIRCLE_SEGMENTS = 32;
12658
+ const FRAME_HEIGHT_RATIO = .48;
12659
+ const MINE_RADIUS_RATIO = .075;
12660
+ const LABEL_SIZE_RATIO = .14;
12661
+ const LABEL_CLEARANCE_RATIO = .11;
12662
+ /** Unit-circle offsets, built once — a mine ring is rotation-invariant. */
12663
+ const UNIT_CIRCLE = Array.from({ length: CIRCLE_SEGMENTS }, (_, index) => {
12664
+ const angle = index / CIRCLE_SEGMENTS * Math.PI * 2;
12665
+ return [Math.cos(angle), Math.sin(angle)];
12666
+ });
12667
+ /** Closes a ring in place by repeating its first vertex, avoiding a re-unproject. */
12668
+ function closeRing(ring) {
12669
+ ring.push(ring[0]);
12670
+ return ring;
12671
+ }
12672
+ /** A closed ring of `CIRCLE_SEGMENTS + 1` positions, the last repeating the first. */
12673
+ function circleRing(center, radius) {
12674
+ return closeRing(UNIT_CIRCLE.map(([x, y]) => toPosition(vecAdd(center, [x * radius, y * radius]))));
12675
+ }
12676
+ function line(points) {
12677
+ return points.map(toPosition);
12678
+ }
12679
+ /** Creates the frame and three Modifier 1 mine glyphs around the center anchor. */
12680
+ function createMinefield(coordinates, options = {}, textAmplifiers = {}, context = {}) {
12681
+ const anchor = coordinates[0];
12682
+ const center = project(anchor[0], anchor[1]);
12683
+ const mineType = options.mineType ?? DEFAULT_MINEFIELD_OPTIONS.mineType;
12684
+ const rotation = (options.rotation ?? DEFAULT_MINEFIELD_OPTIONS.rotation) * Math.PI / 180;
12685
+ const cosRotation = Math.cos(rotation);
12686
+ const sinRotation = Math.sin(rotation);
12687
+ const offset = (origin, x, y) => vecAdd(origin, [x * cosRotation + y * sinRotation, -x * sinRotation + y * cosRotation]);
12688
+ const pixelSize = options.sizePixels ?? (options.sizeMeters === void 0 ? DEFAULT_MINEFIELD_OPTIONS.sizePixels : void 0);
12689
+ const width = pixelSize !== void 0 && options.metersPerPixel !== void 0 && options.metersPerPixel > 0 ? pixelSize * options.metersPerPixel : options.sizeMeters ?? DEFAULT_MINEFIELD_SIZE_METERS;
12690
+ if (!Number.isFinite(width) || width <= 0) return {
12691
+ type: "FeatureCollection",
12692
+ features: []
12693
+ };
12694
+ const height = width * FRAME_HEIGHT_RATIO;
12695
+ const radius = width * MINE_RADIUS_RATIO;
12696
+ const mineCenters = [
12697
+ -.25,
12698
+ 0,
12699
+ .25
12700
+ ].map((ratio) => offset(center, width * ratio, 0));
12701
+ const halfWidth = width / 2;
12702
+ const halfHeight = height / 2;
12703
+ const frameVerts = [
12704
+ offset(center, -halfWidth, -halfHeight),
12705
+ offset(center, -halfWidth, halfHeight),
12706
+ offset(center, halfWidth, halfHeight),
12707
+ offset(center, halfWidth, -halfHeight)
12708
+ ];
12709
+ const frameRing = closeRing([...frameVerts]);
12710
+ const labelRotation = HORIZONTAL_LABEL_ROTATION - rotation;
12711
+ const labelSize = width * LABEL_SIZE_RATIO;
12712
+ const sizeProps = { textSizeMeters: labelSize };
12713
+ const labelFeatures = [];
12714
+ let frameGaps = [];
12715
+ if (textAmplifiers.H) pushLabel(labelFeatures, offset(center, 0, halfHeight + width * LABEL_CLEARANCE_RATIO), textAmplifiers.H, labelRotation, sizeProps, void 0, "H");
12716
+ if (textAmplifiers.N) frameGaps = pushHostileMarkers(labelFeatures, frameRing, textAmplifiers.N, [{
12717
+ side: "west",
12718
+ point: offset(center, -halfWidth, 0)
12719
+ }, {
12720
+ side: "east",
12721
+ point: offset(center, halfWidth, 0)
12722
+ }], {
12723
+ rotation: labelRotation,
12724
+ textHeight: labelSize,
12725
+ clearance: ENY_CLEARANCE_RATIO * labelSize,
12726
+ sizeProps,
12727
+ followPlacementRotation: true
12728
+ }, context.amplifierPlacements);
12729
+ if (textAmplifiers.W) pushLabel(labelFeatures, offset(center, 0, -halfHeight - width * LABEL_CLEARANCE_RATIO), textAmplifiers.W, labelRotation, sizeProps, void 0, "W");
12730
+ const features = [{
12731
+ type: "Feature",
12732
+ properties: { part: "frame" },
12733
+ geometry: frameGaps.length > 0 ? {
12734
+ type: "MultiLineString",
12735
+ coordinates: buildGappedLine(frameRing, frameGaps)
12736
+ } : {
12737
+ type: "LineString",
12738
+ coordinates: closeRing(line(frameVerts))
12739
+ }
12740
+ }, ...labelFeatures];
12741
+ const circles = mineCenters.map((mineCenter) => circleRing(mineCenter, radius));
12742
+ if (mineType === "unspecified") {
12743
+ features.push({
12744
+ type: "Feature",
12745
+ properties: { part: "mines" },
12746
+ geometry: {
12747
+ type: "MultiLineString",
12748
+ coordinates: circles
12749
+ }
12750
+ });
12751
+ return {
12752
+ type: "FeatureCollection",
12753
+ features
12754
+ };
12755
+ }
12756
+ const filledRings = circles.map((ring) => [ring]);
12757
+ const details = [];
12758
+ if (mineType === "antipersonnel" || mineType === "antipersonnel-directional") for (const mineCenter of mineCenters) details.push(line([offset(mineCenter, -radius * .55, radius * .7), offset(mineCenter, -radius * 1.35, radius * 1.55)]), line([offset(mineCenter, radius * .55, radius * .7), offset(mineCenter, radius * 1.35, radius * 1.55)]));
12759
+ if (mineType === "antipersonnel-directional") for (const mineCenter of mineCenters) {
12760
+ const shaftEnd = offset(mineCenter, radius * 1.45, 0);
12761
+ const tip = offset(mineCenter, radius * 1.9, 0);
12762
+ details.push(line([offset(mineCenter, radius * .75, 0), shaftEnd]));
12763
+ filledRings.push([closeRing(line([
12764
+ tip,
12765
+ offset(shaftEnd, 0, radius * .25),
12766
+ offset(shaftEnd, 0, -radius * .25)
12767
+ ]))]);
12768
+ }
12769
+ if (mineType === "antitank-antihandling") for (const mineCenter of mineCenters) details.push(line([
12770
+ offset(mineCenter, 0, -radius * .75),
12771
+ offset(mineCenter, 0, -radius * 1.75),
12772
+ offset(mineCenter, radius * .4, -radius * 1.45)
12773
+ ]));
12774
+ if (mineType === "wide-area-antitank") {
12775
+ const touchX = radius * .55;
12776
+ const touchY = -Math.sqrt(radius * radius - touchX * touchX);
12777
+ const troughX = radius * 1.05;
12778
+ const troughY = -radius * 1.45;
12779
+ const outerX = radius * 1.45;
12780
+ const peakY = -radius * .8;
12781
+ for (const mineCenter of mineCenters) details.push(line([
12782
+ offset(mineCenter, -outerX, peakY),
12783
+ offset(mineCenter, -troughX, troughY),
12784
+ offset(mineCenter, -touchX, touchY)
12785
+ ]), line([
12786
+ offset(mineCenter, touchX, touchY),
12787
+ offset(mineCenter, troughX, troughY),
12788
+ offset(mineCenter, outerX, peakY)
12789
+ ]));
12790
+ }
12791
+ features.push({
12792
+ type: "Feature",
12793
+ properties: {
12794
+ part: "mine-fill",
12795
+ fill: true,
12796
+ style: SOLID_ACCENT_FILL
12797
+ },
12798
+ geometry: {
12799
+ type: "MultiPolygon",
12800
+ coordinates: filledRings
12801
+ }
12802
+ });
12803
+ if (details.length > 0) features.push({
12804
+ type: "Feature",
12805
+ properties: { part: "mine-details" },
12806
+ geometry: {
12807
+ type: "MultiLineString",
12808
+ coordinates: details
12809
+ }
12810
+ });
12811
+ return {
12812
+ type: "FeatureCollection",
12813
+ features
12814
+ };
12815
+ }
12816
+ const MINEFIELD = defineControlMeasure({
12817
+ metadata: MINEFIELD_METADATA,
12818
+ generator: createMinefield,
12819
+ defaultOptions: DEFAULT_MINEFIELD_OPTIONS,
12820
+ rule: staticPointDrawRule,
12821
+ transformOptions(options, { scale, rotationRadians }) {
12822
+ const patch = {};
12823
+ if (scale !== 1 && Number.isFinite(scale) && scale > 0) if (options.sizePixels !== void 0 || options.sizeMeters === void 0) patch.sizePixels = (options.sizePixels ?? DEFAULT_MINEFIELD_OPTIONS.sizePixels) * scale;
12824
+ else patch.sizeMeters = options.sizeMeters * scale;
12825
+ if (rotationRadians !== 0 && Number.isFinite(rotationRadians)) patch.rotation = normalizeDegrees((options.rotation ?? DEFAULT_MINEFIELD_OPTIONS.rotation) + rotationRadians * 180 / Math.PI);
12826
+ return Object.keys(patch).length > 0 ? patch : void 0;
12827
+ },
12828
+ previewSample: {
12829
+ controlPoints: [[0, 0]],
12830
+ options: { sizeMeters: 1e3 },
12831
+ textAmplifiers: {
12832
+ H: "+S",
12833
+ N: "ENY",
12834
+ W: "032400ZJUL2007"
12835
+ }
12836
+ }
12837
+ });
12838
+ //#endregion
12839
+ //#region src/generators/cm27-protection-areas/mine-areas.ts
12840
+ const DEFAULT_MINE_AREA_OPTIONS = {
12841
+ mineType: "unspecified",
12842
+ smooth: false,
12843
+ smoothResolution: 16
12844
+ };
12845
+ const COMMON_METADATA = {
12846
+ entity: "Protection Areas",
12847
+ minCoordinates: 3,
12848
+ geometry: "area",
12849
+ geometryTypes: [
12850
+ "Polygon",
12851
+ "MultiLineString",
12852
+ "Point"
12853
+ ],
12854
+ paints: {
12855
+ stroke: true,
12856
+ fill: "fixed",
12857
+ text: true
12858
+ },
12859
+ drawRule: "Area1",
12860
+ capturesLabelSize: true,
12861
+ params: [
12862
+ MINE_TYPE_PARAM,
12863
+ ...AREA_SMOOTH_PARAMS,
12864
+ AREA_LABEL_PADDING_PARAM
12865
+ ],
12866
+ textAmplifiers: [AREA_HOSTILE_AMPLIFIER]
12867
+ };
12868
+ const DYNAMIC_MINEFIELD_METADATA = {
12869
+ ...COMMON_METADATA,
12870
+ id: "minefield-dynamic",
12871
+ name: "Minefield (Dynamic)",
12872
+ description: "A free-area minefield filled with the selected Modifier 1 mine pictogram.",
12873
+ entityType: "Minefield Symbol",
12874
+ entitySubtype: "Minefield (Dynamic)",
12875
+ value: "270707"
12876
+ };
12877
+ const MINED_AREA_METADATA = {
12878
+ ...COMMON_METADATA,
12879
+ id: "mined-area",
12880
+ name: "Mined Area",
12881
+ description: "An area dangerous because of the presence or suspected presence of mines.",
12882
+ entityType: "Mined Area",
12883
+ value: "270800"
12884
+ };
12885
+ function axisIntersections(ring, axis, target) {
12886
+ const other = axis === 0 ? 1 : 0;
12887
+ const intersections = [];
12888
+ for (let index = 0; index < ring.length - 1; index++) {
12889
+ const a = ring[index];
12890
+ const b = ring[index + 1];
12891
+ const av = a[axis];
12892
+ const bv = b[axis];
12893
+ if (Math.min(av, bv) <= target && target < Math.max(av, bv)) {
12894
+ const ratio = (target - av) / (bv - av);
12895
+ const point = [0, 0];
12896
+ point[axis] = target;
12897
+ point[other] = a[other] + ratio * (b[other] - a[other]);
12898
+ intersections.push(point);
12899
+ }
12900
+ }
12901
+ return intersections;
12902
+ }
12903
+ function cardinalBoundaryPoints(ring, sideOffset = 0) {
12904
+ const center = ringLabelAnchor(ring);
12905
+ const fallback = ring.slice(0, -1);
12906
+ const scans = /* @__PURE__ */ new Map();
12907
+ const extremeAt = (fixedAxis, target, resultAxis, direction) => {
12908
+ const key = `${fixedAxis}:${target}`;
12909
+ let crossings = scans.get(key);
12910
+ if (!crossings) {
12911
+ crossings = axisIntersections(ring, fixedAxis, target);
12912
+ scans.set(key, crossings);
12913
+ }
12914
+ return (crossings.length > 0 ? crossings : fallback).reduce((best, point) => point[resultAxis] * direction > best[resultAxis] * direction ? point : best);
12915
+ };
12916
+ return [
12917
+ extremeAt(0, center[0], 1, 1),
12918
+ extremeAt(1, center[1] + sideOffset, 0, 1),
12919
+ extremeAt(0, center[0], 1, -1),
12920
+ extremeAt(1, center[1] - sideOffset, 0, -1)
12921
+ ];
12922
+ }
12923
+ function createMineArea(positions, options, minedArea, textAmplifiers, context) {
12924
+ const ring = buildClosedRing(positions, options.smooth ?? DEFAULT_MINE_AREA_OPTIONS.smooth, options.smoothResolution ?? DEFAULT_MINE_AREA_OPTIONS.smoothResolution, 16);
12925
+ const mineType = options.mineType ?? DEFAULT_MINE_AREA_OPTIONS.mineType;
12926
+ const labelFeatures = [];
12927
+ const sideOffset = textAmplifiers.N ? resolveLabelOffsetMeters(options, 1.5) : 0;
12928
+ return {
12929
+ type: "FeatureCollection",
12930
+ features: [...patternedAreaFeatures(ring, [...minedArea ? pushBoundaryMarkers(labelFeatures, ring, "M", cardinalBoundaryPoints(ring, sideOffset).map((point) => ({ point })), {
12931
+ rotation: HORIZONTAL_LABEL_ROTATION,
12932
+ textHeight: resolveLabelOffsetMeters(options, 1),
12933
+ clearance: resolveLabelOffsetMeters(options, .12),
12934
+ sizeProps: labelSizeProps(options)
12935
+ }) : [], ...pushAreaLabels(labelFeatures, ring, { hostile: textAmplifiers.N }, options, context.amplifierPlacements)], mineFillPattern(mineType)), ...labelFeatures]
12936
+ };
12937
+ }
12938
+ function createDynamicMinefield(positions, options = {}, textAmplifiers = {}, context = {}) {
12939
+ return createMineArea(positions, options, false, textAmplifiers, context);
12940
+ }
12941
+ function createMinedArea(positions, options = {}, textAmplifiers = {}, context = {}) {
12942
+ return createMineArea(positions, options, true, textAmplifiers, context);
12943
+ }
12944
+ const PREVIEW_POINTS = [
12945
+ [-1, -.55],
12946
+ [1, -.55],
12947
+ [1, .55],
12948
+ [-1, .55]
12949
+ ];
12950
+ const DYNAMIC_MINEFIELD = defineControlMeasure({
12951
+ metadata: DYNAMIC_MINEFIELD_METADATA,
12952
+ generator: createDynamicMinefield,
12953
+ defaultOptions: DEFAULT_MINE_AREA_OPTIONS,
12954
+ rule: area1DrawRule,
12955
+ previewSample: { controlPoints: PREVIEW_POINTS }
12956
+ });
12957
+ const MINED_AREA = defineControlMeasure({
12958
+ metadata: MINED_AREA_METADATA,
12959
+ generator: createMinedArea,
12960
+ defaultOptions: DEFAULT_MINE_AREA_OPTIONS,
12961
+ rule: area1DrawRule,
12962
+ previewSample: {
12963
+ controlPoints: PREVIEW_POINTS,
12964
+ options: { labelSizePixels: 22 }
12965
+ }
12966
+ });
12967
+ //#endregion
12377
12968
  //#region src/generators/cm27-protection-areas/params.ts
12378
12969
  const OBSTACLE_BYPASS_PARAMS = [
12379
12970
  {
12380
12971
  key: "arrowheadLengthRatio",
12972
+ presentationTier: "advanced",
12381
12973
  label: "Arrowhead length",
12382
12974
  description: "Arrowhead length as a ratio of the opening width",
12383
12975
  type: "number",
@@ -12387,6 +12979,7 @@ const OBSTACLE_BYPASS_PARAMS = [
12387
12979
  },
12388
12980
  {
12389
12981
  key: "arrowheadWidthRatio",
12982
+ presentationTier: "advanced",
12390
12983
  label: "Arrowhead width",
12391
12984
  description: "Arrowhead base width as a ratio of the opening width",
12392
12985
  type: "number",
@@ -12396,6 +12989,7 @@ const OBSTACLE_BYPASS_PARAMS = [
12396
12989
  },
12397
12990
  {
12398
12991
  key: "defaultLengthRatio",
12992
+ presentationTier: "advanced",
12399
12993
  label: "Default length",
12400
12994
  description: "Symbol depth as a ratio of opening width when no hint point is given",
12401
12995
  type: "number",
@@ -12434,6 +13028,7 @@ const OBSTACLE_BYPASS_DIFFICULT_METADATA = {
12434
13028
  ...OBSTACLE_BYPASS_PARAMS,
12435
13029
  {
12436
13030
  key: "zigzagAmplitudeRatio",
13031
+ presentationTier: "advanced",
12437
13032
  label: "Zigzag amplitude",
12438
13033
  description: "Zigzag tooth depth as a ratio of the opening width.",
12439
13034
  type: "number",
@@ -12443,6 +13038,7 @@ const OBSTACLE_BYPASS_DIFFICULT_METADATA = {
12443
13038
  },
12444
13039
  {
12445
13040
  key: "zigzagSpacingRatio",
13041
+ presentationTier: "advanced",
12446
13042
  label: "Zigzag spacing",
12447
13043
  description: "Spacing between zigzag teeth as a ratio of the opening width.",
12448
13044
  type: "number",
@@ -12686,6 +13282,7 @@ const OBSTACLE_BYPASS_IMPOSSIBLE_METADATA = {
12686
13282
  ...OBSTACLE_BYPASS_PARAMS,
12687
13283
  {
12688
13284
  key: "rearBarLengthRatio",
13285
+ presentationTier: "advanced",
12689
13286
  label: "Rear bar length",
12690
13287
  description: "Length of each rear barrier bar as a ratio of the opening width.",
12691
13288
  type: "number",
@@ -12695,6 +13292,7 @@ const OBSTACLE_BYPASS_IMPOSSIBLE_METADATA = {
12695
13292
  },
12696
13293
  {
12697
13294
  key: "rearGapRatio",
13295
+ presentationTier: "advanced",
12698
13296
  label: "Rear gap",
12699
13297
  description: "Gap between the two rear bars as a ratio of the opening width.",
12700
13298
  type: "number",
@@ -13046,6 +13644,7 @@ const PRINCIPAL_DIRECTION_OF_FIRE_METADATA = {
13046
13644
  drawRule: "Line3",
13047
13645
  params: [{
13048
13646
  key: "arrowheadLengthRatio",
13647
+ presentationTier: "advanced",
13049
13648
  label: "Arrowhead length",
13050
13649
  description: "Arrowhead length as a ratio of each arm's length",
13051
13650
  type: "number",
@@ -13054,6 +13653,7 @@ const PRINCIPAL_DIRECTION_OF_FIRE_METADATA = {
13054
13653
  step: .01
13055
13654
  }, {
13056
13655
  key: "arrowheadWidthRatio",
13656
+ presentationTier: "advanced",
13057
13657
  label: "Arrowhead width",
13058
13658
  description: "Arrowhead base width as a multiple of the arrowhead length",
13059
13659
  type: "number",
@@ -13132,6 +13732,7 @@ const SECONDARY_DIRECTION_OF_FIRE_METADATA = {
13132
13732
  drawRule: "Line3",
13133
13733
  params: [{
13134
13734
  key: "arrowheadLengthRatio",
13735
+ presentationTier: "advanced",
13135
13736
  label: "Arrowhead length",
13136
13737
  description: "Arrowhead length as a ratio of each arm's length",
13137
13738
  type: "number",
@@ -13140,6 +13741,7 @@ const SECONDARY_DIRECTION_OF_FIRE_METADATA = {
13140
13741
  step: .01
13141
13742
  }, {
13142
13743
  key: "arrowheadWidthRatio",
13744
+ presentationTier: "advanced",
13143
13745
  label: "Arrowhead width",
13144
13746
  description: "Arrowhead base width as a multiple of the arrowhead length",
13145
13747
  type: "number",
@@ -13647,6 +14249,7 @@ const TURN_METADATA = {
13647
14249
  params: [
13648
14250
  {
13649
14251
  key: "arrowheadLengthRatio",
14252
+ presentationTier: "advanced",
13650
14253
  label: "Arrowhead length",
13651
14254
  description: "Arrowhead length as a ratio of the rear-to-tip distance",
13652
14255
  type: "number",
@@ -13656,6 +14259,7 @@ const TURN_METADATA = {
13656
14259
  },
13657
14260
  {
13658
14261
  key: "arrowheadWidthRatio",
14262
+ presentationTier: "advanced",
13659
14263
  label: "Arrowhead width",
13660
14264
  description: "Arrowhead base width as a ratio of the rear-to-tip distance",
13661
14265
  type: "number",
@@ -13665,6 +14269,7 @@ const TURN_METADATA = {
13665
14269
  },
13666
14270
  {
13667
14271
  key: "arcSegments",
14272
+ presentationTier: "advanced",
13668
14273
  label: "Arc segments",
13669
14274
  description: "Number of line segments approximating the quarter-circle shaft.",
13670
14275
  type: "number",
@@ -13750,6 +14355,7 @@ const DEFAULT_TURNING_MOVEMENT_OPTIONS = {
13750
14355
  };
13751
14356
  const TURNING_MOVEMENT_PARAMS = [{
13752
14357
  key: "crossbarPosition",
14358
+ presentationTier: "advanced",
13753
14359
  label: "Crossbar position",
13754
14360
  description: "Position along the shaft, from tail (0) to arrowhead base (1)",
13755
14361
  type: "number",
@@ -13826,6 +14432,8 @@ const DEFINITIONS = {
13826
14432
  "landing-zone": LANDING_ZONE,
13827
14433
  "limited-access-area": LIMITED_ACCESS_AREA,
13828
14434
  "no-fire-area-irregular": NO_FIRE_AREA_IRREGULAR,
14435
+ "minefield-dynamic": DYNAMIC_MINEFIELD,
14436
+ "mined-area": MINED_AREA,
13829
14437
  "pickup-zone": PICKUP_ZONE,
13830
14438
  "assault-position": ASSAULT_POSITION,
13831
14439
  "attack-position": ATTACK_POSITION,
@@ -13909,6 +14517,7 @@ const DEFINITIONS = {
13909
14517
  fix: FIX,
13910
14518
  "fix-mission-task": FIX_MISSION_TASK,
13911
14519
  turn: TURN,
14520
+ minefield: MINEFIELD,
13912
14521
  "obstacle-bypass-easy": OBSTACLE_BYPASS_EASY,
13913
14522
  "obstacle-bypass-difficult": OBSTACLE_BYPASS_DIFFICULT,
13914
14523
  "obstacle-bypass-impossible": OBSTACLE_BYPASS_IMPOSSIBLE
@@ -14275,4 +14884,4 @@ function assertNever(value) {
14275
14884
  throw new Error(`Unhandled control measure kind: ${String(value)}`);
14276
14885
  }
14277
14886
  //#endregion
14278
- export { DEFAULT_COUNTERATTACK_BY_FIRE_OPTIONS as $, createMidpointPerpendicularDrawRule as $t, DEFAULT_PENETRATE_OPTIONS as A, TEXT_AMPLIFIER_FIELDS as At, DEFAULT_PHASE_LINE_OPTIONS as B, line26DrawRule as Bt, DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS as C, DEFAULT_ANTITANK_DITCH_OPTIONS as Ct, DEFAULT_SCREEN_OPTIONS as D, DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS as Dt, DEFAULT_SEIZE_OPTIONS as E, DEFAULT_AREA_DEFENSE_OPTIONS as Et, DEFAULT_HANDOVER_LINE_OPTIONS as F, DEFAULT_AIRBORNE_ATTACK_OPTIONS as Ft, DEFAULT_ENCIRCLEMENT_OPTIONS as G, ambushDrawRule as Gt, DEFAULT_FIX_MISSION_TASK_OPTIONS as H, line23DrawRule as Ht, DEFAULT_FORWARD_EDGE_OF_BATTLE_AREA_OPTIONS as I, rectangleDrawRule as It, DEFAULT_DISRUPT_MISSION_TASK_OPTIONS as J, penetrateDrawRule as Jt, DEFAULT_DISRUPT_OPTIONS as K, attackByFireDrawRule as Kt, DEFAULT_RELEASE_LINE_OPTIONS as L, axis1DrawRule as Lt, DEFAULT_FORTIFIED_AREA_OPTIONS as M, normalizeTextAmplifiers as Mt, DEFAULT_FORTIFIED_LINE_OPTIONS as N, resolveAmplifierPlacement as Nt, DEFAULT_RETIRE_OPTIONS as O, DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS as Ot, DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS as P, DEFAULT_AMBUSH_OPTIONS as Pt, DEFAULT_TACTICAL_ARROW_OPTIONS as Q, computeDefaultMidpointPerpendicularPoint as Qt, DEFAULT_HOLDING_LINE_OPTIONS as R, supportByFireDrawRule as Rt, DEFAULT_LANDING_ZONE_OPTIONS as S, DEFAULT_ANTITANK_WALL_OPTIONS as St, DEFAULT_WITHDRAW_OPTIONS as T, DEFAULT_AREA_OF_OPERATIONS_OPTIONS as Tt, DEFAULT_FIX_OPTIONS as U, turnDrawRule as Ut, DEFAULT_FLOT_OPTIONS as V, line24DrawRule as Vt, DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS as W, line1DrawRule as Wt, DEFAULT_DELAY_OPTIONS as X, disruptDrawRule as Xt, DEFAULT_DISENGAGE_OPTIONS as Y, centerRadiusDrawRule as Yt, DEFAULT_COVER_OPTIONS as Z, blockDrawRule as Zt, DEFAULT_PICKUP_ZONE_OPTIONS as _, DEFAULT_BLOCK_ARROW_OPTIONS as _t, DEFINITIONS as a, computeInitialWidthPoint as an, DEFAULT_GENERIC_POLYGON_OPTIONS as at, DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS as b, DEFAULT_ATTACK_HELICOPTER_OPTIONS as bt, getDefaultOptions as c, unproject as cn, DEFAULT_CLASSIC_ARROW_OPTIONS as ct, DEFAULT_TURN_OPTIONS as d, roundToFixed as dn, DEFAULT_BREACH_OPTIONS as dt, getMidpointPerpendicularSignedDistance as en, DEFAULT_COUNTERATTACK_OPTIONS as et, DEFAULT_SUPPORT_BY_FIRE_OPTIONS as f, DEFAULT_BLOCK_MISSION_TASK_OPTIONS as ft, DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS as g, DEFAULT_BOUNDARY_OPTIONS as gt, SECONDARY_DIRECTION_OF_FIRE_DASH as h, DEFAULT_LIGHT_LINE_OPTIONS as ht, CONTROL_MEASURE_METADATA as i, calculateMetrics as in, DEFAULT_GENERIC_RECTANGLE_OPTIONS as it, DEFAULT_FRONTAL_ATTACK_OPTIONS as j, canonicalTextAmplifierKey as jt, DEFAULT_REARWARD_PASSAGE_OF_LINES_OPTIONS as k, DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS as kt, listControlMeasureMetadata as l, EPSILON as ln, DEFAULT_CANALIZE_OPTIONS as lt, DEFAULT_SECONDARY_DIRECTION_OF_FIRE_OPTIONS as m, DEFAULT_ENGINEER_WORK_LINE_OPTIONS as mt, resolveStyleHints as n, snapToMidpointPerpendicular as nn, DEFAULT_CLEAR_OPTIONS as nt, getControlMeasureMetadata as o, haversineDistance as on, DEFAULT_GENERIC_LINE_OPTIONS as ot, DEFAULT_STRONG_POINT_OPTIONS as p, DEFAULT_GENERIC_C2_LINE_OPTIONS as pt, DEFAULT_GUARD_OPTIONS as q, point12DrawRule as qt, CONTROL_MEASURE_IDS as r, createBaselineFrame as rn, DEFAULT_GENERIC_TEXT_OPTIONS as rt, getControlMeasureMetadataByValue as s, project as sn, DEFAULT_GENERIC_CIRCLE_OPTIONS as st, renderControlMeasure as t, pointOnMidpointPerpendicularAxis as tn, DEFAULT_SUPPORTING_ATTACK_OPTIONS as tt, DEFAULT_TURNING_MOVEMENT_OPTIONS as u, getMetersPerPixel as un, DEFAULT_BYPASS_OPTIONS as ut, DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS as v, DEFAULT_BLOCK_OPTIONS as vt, DEFAULT_WITHDRAW_UNDER_PRESSURE_OPTIONS as w, DEFAULT_ASSEMBLY_AREA_OPTIONS as wt, DEFAULT_MAIN_ATTACK_OPTIONS as x, DEFAULT_ATTACK_BY_FIRE_OPTIONS as xt, DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS as y, DEFAULT_BATTLE_POSITION_OPTIONS as yt, DEFAULT_BRIDGEHEAD_LINE_OPTIONS as z, line27DrawRule as zt };
14887
+ export { DEFAULT_TACTICAL_ARROW_OPTIONS as $, blockDrawRule as $t, DEFAULT_REARWARD_PASSAGE_OF_LINES_OPTIONS as A, DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS as At, DEFAULT_BRIDGEHEAD_LINE_OPTIONS as B, line27DrawRule as Bt, DEFAULT_LANDING_ZONE_OPTIONS as C, DEFAULT_ANTITANK_WALL_OPTIONS as Ct, DEFAULT_SEIZE_OPTIONS as D, DEFAULT_AREA_DEFENSE_OPTIONS as Dt, DEFAULT_WITHDRAW_OPTIONS as E, DEFAULT_AREA_OF_OPERATIONS_OPTIONS as Et, DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS as F, DEFAULT_AMBUSH_OPTIONS as Ft, DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS as G, line1DrawRule as Gt, DEFAULT_FLOT_OPTIONS as H, line24DrawRule as Ht, DEFAULT_HANDOVER_LINE_OPTIONS as I, DEFAULT_AIRBORNE_ATTACK_OPTIONS as It, DEFAULT_GUARD_OPTIONS as J, staticPointDrawRule as Jt, DEFAULT_ENCIRCLEMENT_OPTIONS as K, ambushDrawRule as Kt, DEFAULT_FORWARD_EDGE_OF_BATTLE_AREA_OPTIONS as L, rectangleDrawRule as Lt, DEFAULT_FRONTAL_ATTACK_OPTIONS as M, canonicalTextAmplifierKey as Mt, DEFAULT_FORTIFIED_AREA_OPTIONS as N, normalizeTextAmplifiers as Nt, DEFAULT_SCREEN_OPTIONS as O, DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS as Ot, DEFAULT_FORTIFIED_LINE_OPTIONS as P, resolveAmplifierPlacement as Pt, DEFAULT_COVER_OPTIONS as Q, disruptDrawRule as Qt, DEFAULT_RELEASE_LINE_OPTIONS as R, axis1DrawRule as Rt, DEFAULT_MAIN_ATTACK_OPTIONS as S, DEFAULT_ATTACK_BY_FIRE_OPTIONS as St, DEFAULT_WITHDRAW_UNDER_PRESSURE_OPTIONS as T, DEFAULT_ASSEMBLY_AREA_OPTIONS as Tt, DEFAULT_FIX_MISSION_TASK_OPTIONS as U, line23DrawRule as Ut, DEFAULT_PHASE_LINE_OPTIONS as V, line26DrawRule as Vt, DEFAULT_FIX_OPTIONS as W, turnDrawRule as Wt, DEFAULT_DISENGAGE_OPTIONS as X, penetrateDrawRule as Xt, DEFAULT_DISRUPT_MISSION_TASK_OPTIONS as Y, point12DrawRule as Yt, DEFAULT_DELAY_OPTIONS as Z, centerRadiusDrawRule as Zt, DEFAULT_PICKUP_ZONE_OPTIONS as _, DEFAULT_BOUNDARY_OPTIONS as _t, DEFINITIONS as a, createBaselineFrame as an, DEFAULT_GENERIC_RECTANGLE_OPTIONS as at, DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS as b, DEFAULT_BATTLE_POSITION_OPTIONS as bt, getDefaultOptions as c, haversineDistance as cn, DEFAULT_GENERIC_CIRCLE_OPTIONS as ct, DEFAULT_TURN_OPTIONS as d, EPSILON as dn, DEFAULT_BYPASS_OPTIONS as dt, computeDefaultMidpointPerpendicularPoint as en, DEFAULT_COUNTERATTACK_BY_FIRE_OPTIONS as et, DEFAULT_SUPPORT_BY_FIRE_OPTIONS as f, getMetersPerPixel as fn, DEFAULT_BREACH_OPTIONS as ft, DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS as g, DEFAULT_LIGHT_LINE_OPTIONS as gt, SECONDARY_DIRECTION_OF_FIRE_DASH as h, DEFAULT_ENGINEER_WORK_LINE_OPTIONS as ht, CONTROL_MEASURE_METADATA as i, snapToMidpointPerpendicular as in, DEFAULT_GENERIC_TEXT_OPTIONS as it, DEFAULT_PENETRATE_OPTIONS as j, TEXT_AMPLIFIER_FIELDS as jt, DEFAULT_RETIRE_OPTIONS as k, DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS as kt, listControlMeasureMetadata as l, project as ln, DEFAULT_CLASSIC_ARROW_OPTIONS as lt, DEFAULT_SECONDARY_DIRECTION_OF_FIRE_OPTIONS as m, DEFAULT_GENERIC_C2_LINE_OPTIONS as mt, resolveStyleHints as n, getMidpointPerpendicularSignedDistance as nn, DEFAULT_SUPPORTING_ATTACK_OPTIONS as nt, getControlMeasureMetadata as o, calculateMetrics as on, DEFAULT_GENERIC_POLYGON_OPTIONS as ot, DEFAULT_STRONG_POINT_OPTIONS as p, roundToFixed as pn, DEFAULT_BLOCK_MISSION_TASK_OPTIONS as pt, DEFAULT_DISRUPT_OPTIONS as q, attackByFireDrawRule as qt, CONTROL_MEASURE_IDS as r, pointOnMidpointPerpendicularAxis as rn, DEFAULT_CLEAR_OPTIONS as rt, getControlMeasureMetadataByValue as s, computeInitialWidthPoint as sn, DEFAULT_GENERIC_LINE_OPTIONS as st, renderControlMeasure as t, createMidpointPerpendicularDrawRule as tn, DEFAULT_COUNTERATTACK_OPTIONS as tt, DEFAULT_TURNING_MOVEMENT_OPTIONS as u, unproject as un, DEFAULT_CANALIZE_OPTIONS as ut, DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS as v, DEFAULT_BLOCK_ARROW_OPTIONS as vt, DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS as w, DEFAULT_ANTITANK_DITCH_OPTIONS as wt, DEFAULT_MINEFIELD_OPTIONS as x, DEFAULT_ATTACK_HELICOPTER_OPTIONS as xt, DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS as y, DEFAULT_BLOCK_OPTIONS as yt, DEFAULT_HOLDING_LINE_OPTIONS as z, supportByFireDrawRule as zt };