@orbat-mapper/control-measures 0.21.0 → 0.22.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.
@@ -1,40 +1,3 @@
1
- //#region src/style.ts
2
- /**
3
- * Per-feature style hint pinning a filled part to a solid interior. Attach to
4
- * a generator's intrinsic doctrinal accents — arrowheads, teeth, echelon
5
- * glyphs, barbs, blades — so a patterned (`hatch`, `dots`, …) fill set at the graphicsStyle
6
- * or measure layer never bleeds into a small silhouette and ruins its
7
- * legibility. The renderer only reads style hints, so one shared instance is
8
- * safe to reuse across every accent feature.
9
- */
10
- const SOLID_ACCENT_FILL = { fillPattern: "solid" };
11
- /**
12
- * Ultimate fallback for the symbol color when no `color` or per-channel
13
- * override is supplied at any layer. Keeps a zero-config render monocolor
14
- * black and guarantees filled parts still render filled. See ADR-0011.
15
- */
16
- const DEFAULT_SYMBOL_COLOR = "#000000";
17
- //#endregion
18
- //#region src/portrayal.ts
19
- const DEFAULT_STROKE_WIDTH_CSS_PIXELS = 2;
20
- const DEFAULT_STROKE_DASH_CSS_PIXELS = Object.freeze([]);
21
- const DEFAULT_LINE_CAP = "round";
22
- const DEFAULT_LINE_JOIN = "round";
23
- const DEFAULT_LABEL_HEIGHT_CSS_PIXELS = 14;
24
- const DEFAULT_LABEL_SIZE_CLAMP_CSS_PIXELS = {
25
- min: 8,
26
- max: 24
27
- };
28
- /** Shared absent-value portrayal defaults; render output remains sparse. */
29
- const DEFAULT_PORTRAYAL = Object.freeze({
30
- symbolColor: DEFAULT_SYMBOL_COLOR,
31
- strokeWidthCssPixels: 2,
32
- strokeDashCssPixels: DEFAULT_STROKE_DASH_CSS_PIXELS,
33
- lineCap: DEFAULT_LINE_CAP,
34
- lineJoin: DEFAULT_LINE_JOIN,
35
- labelHeightCssPixels: 14
36
- });
37
- //#endregion
38
1
  //#region src/define.ts
39
2
  /**
40
3
  * Identity helper that infers a definition's literal `Id` and precise generator
@@ -1809,6 +1772,43 @@ const line25DrawRule = {
1809
1772
  transform: (event) => clonePositions(event.next.slice(0, 2))
1810
1773
  };
1811
1774
  //#endregion
1775
+ //#region src/style.ts
1776
+ /**
1777
+ * Per-feature style hint pinning a filled part to a solid interior. Attach to
1778
+ * a generator's intrinsic doctrinal accents — arrowheads, teeth, echelon
1779
+ * glyphs, barbs, blades — so a patterned (`hatch`, `dots`, …) fill set at the graphicsStyle
1780
+ * or measure layer never bleeds into a small silhouette and ruins its
1781
+ * legibility. The renderer only reads style hints, so one shared instance is
1782
+ * safe to reuse across every accent feature.
1783
+ */
1784
+ const SOLID_ACCENT_FILL = { fillPattern: "solid" };
1785
+ /**
1786
+ * Ultimate fallback for the symbol color when no `color` or per-channel
1787
+ * override is supplied at any layer. Keeps a zero-config render monocolor
1788
+ * black and guarantees filled parts still render filled. See ADR-0011.
1789
+ */
1790
+ const DEFAULT_SYMBOL_COLOR = "#000000";
1791
+ //#endregion
1792
+ //#region src/portrayal.ts
1793
+ const DEFAULT_STROKE_WIDTH_CSS_PIXELS = 2;
1794
+ const DEFAULT_STROKE_DASH_CSS_PIXELS = Object.freeze([]);
1795
+ const DEFAULT_LINE_CAP = "round";
1796
+ const DEFAULT_LINE_JOIN = "round";
1797
+ const DEFAULT_LABEL_HEIGHT_CSS_PIXELS = 14;
1798
+ const DEFAULT_LABEL_SIZE_CLAMP_CSS_PIXELS = {
1799
+ min: 8,
1800
+ max: 24
1801
+ };
1802
+ /** Shared absent-value portrayal defaults; render output remains sparse. */
1803
+ const DEFAULT_PORTRAYAL = Object.freeze({
1804
+ symbolColor: DEFAULT_SYMBOL_COLOR,
1805
+ strokeWidthCssPixels: 2,
1806
+ strokeDashCssPixels: DEFAULT_STROKE_DASH_CSS_PIXELS,
1807
+ lineCap: DEFAULT_LINE_CAP,
1808
+ lineJoin: DEFAULT_LINE_JOIN,
1809
+ labelHeightCssPixels: 14
1810
+ });
1811
+ //#endregion
1812
1812
  //#region src/internal/angle-utils.ts
1813
1813
  /**
1814
1814
  * Wraps an angle (radians) into the half-open range (-π, π].
@@ -2621,6 +2621,408 @@ function fixedLabelLineFeatures(positions, options, textForEnd, hostileText, con
2621
2621
  features
2622
2622
  };
2623
2623
  }
2624
+ function normalizeArcResolution(value) {
2625
+ if (typeof value !== "number" || !Number.isFinite(value)) return 64;
2626
+ return Math.min(360, Math.max(4, Math.round(value)));
2627
+ }
2628
+ const ARC_RESOLUTION_PARAMS = [{
2629
+ key: "resolution",
2630
+ presentationTier: "advanced",
2631
+ label: "Resolution",
2632
+ description: "Number of segments in a full 360° sweep.",
2633
+ type: "number",
2634
+ min: 4,
2635
+ max: 360,
2636
+ step: 1
2637
+ }];
2638
+ //#endregion
2639
+ //#region src/generators/cm29-protection-lines/params.ts
2640
+ const FORTIFIED_PARAMS = [
2641
+ ...SMOOTH_LINE_PARAMS,
2642
+ {
2643
+ key: "toothSizePixels",
2644
+ label: "Tooth size",
2645
+ description: "Side length of the square crenellations",
2646
+ type: "number",
2647
+ min: 5,
2648
+ max: 50,
2649
+ step: 1,
2650
+ unit: "px"
2651
+ },
2652
+ {
2653
+ key: "toothSize",
2654
+ label: "Tooth size",
2655
+ description: "Side length of the square crenellations",
2656
+ type: "number",
2657
+ min: 1,
2658
+ max: 500,
2659
+ step: 1,
2660
+ unit: "m"
2661
+ },
2662
+ LABEL_PADDING_PARAM
2663
+ ];
2664
+ const ANTITANK_DITCH_PARAMS = [
2665
+ ...SMOOTH_LINE_PARAMS,
2666
+ {
2667
+ key: "toothHeightPixels",
2668
+ label: "Tooth height",
2669
+ description: "Perpendicular depth of each triangular tooth",
2670
+ type: "number",
2671
+ min: 5,
2672
+ max: 50,
2673
+ step: 1,
2674
+ unit: "px"
2675
+ },
2676
+ {
2677
+ key: "toothHeight",
2678
+ label: "Tooth height",
2679
+ description: "Perpendicular depth of each triangular tooth",
2680
+ type: "number",
2681
+ min: 1,
2682
+ max: 500,
2683
+ step: 1,
2684
+ unit: "m"
2685
+ },
2686
+ {
2687
+ key: "toothWidthRatio",
2688
+ presentationTier: "advanced",
2689
+ label: "Tooth width ratio",
2690
+ description: "Tooth base span as a multiple of height",
2691
+ type: "number",
2692
+ min: .5,
2693
+ max: 3,
2694
+ step: .05,
2695
+ unit: "x"
2696
+ },
2697
+ LABEL_PADDING_PARAM
2698
+ ];
2699
+ const ANTITANK_WALL_PARAMS = [...ANTITANK_DITCH_PARAMS, {
2700
+ key: "toothSpacingRatio",
2701
+ presentationTier: "advanced",
2702
+ label: "Tooth spacing ratio",
2703
+ description: "Gap between teeth as a multiple of base width",
2704
+ type: "number",
2705
+ min: 0,
2706
+ max: 3,
2707
+ step: .05,
2708
+ unit: "x"
2709
+ }];
2710
+ const WIRE_MARKER_PARAMS = [{
2711
+ key: "markerSize",
2712
+ label: "Marker size",
2713
+ description: "Full height of each wire marker in meters",
2714
+ type: "number",
2715
+ min: 1,
2716
+ max: 500,
2717
+ step: 1,
2718
+ unit: "m"
2719
+ }, {
2720
+ key: "markerSizePixels",
2721
+ label: "Marker size",
2722
+ description: "Full height of each wire marker in pixels",
2723
+ type: "number",
2724
+ min: 1,
2725
+ max: 50,
2726
+ step: 1,
2727
+ unit: "px"
2728
+ }];
2729
+ /** The lower bound varies per wire kind, so callers spread this and override `min`. */
2730
+ const WIRE_SPACING_PARAM = {
2731
+ key: "markerSpacingRatio",
2732
+ label: "Marker spacing",
2733
+ description: "Target distance between marker groups as a multiple of marker height",
2734
+ presentationTier: "advanced",
2735
+ type: "number",
2736
+ min: .8,
2737
+ max: 10,
2738
+ step: .1
2739
+ };
2740
+ //#endregion
2741
+ //#region src/generators/cm29-protection-lines/wire-obstacles.ts
2742
+ const DEFAULT_MARKER_SIZE = 100;
2743
+ const DEFAULT_MARKER_SIZE_PIXELS = 20;
2744
+ const WIRE_KINDS = {
2745
+ unspecified: {
2746
+ subtype: "Unspecified",
2747
+ value: "290301",
2748
+ description: "A wire obstacle whose fence type is unspecified.",
2749
+ spacing: 1.5,
2750
+ minSpacing: .8,
2751
+ concertina: false,
2752
+ oneSided: false,
2753
+ paired: false,
2754
+ rails: 0,
2755
+ railSeparation: 0,
2756
+ previewMarkerSize: 96
2757
+ },
2758
+ single: {
2759
+ subtype: "Single Fence",
2760
+ value: "290302",
2761
+ description: "A wire obstacle consisting of a single fence.",
2762
+ spacing: 3,
2763
+ minSpacing: .8,
2764
+ concertina: false,
2765
+ oneSided: false,
2766
+ paired: false,
2767
+ rails: 1,
2768
+ railSeparation: 0,
2769
+ previewMarkerSize: 115
2770
+ },
2771
+ double: {
2772
+ subtype: "Double Fence",
2773
+ value: "290303",
2774
+ description: "A wire obstacle consisting of a double fence.",
2775
+ spacing: 3.6,
2776
+ minSpacing: 1.6,
2777
+ concertina: false,
2778
+ oneSided: false,
2779
+ paired: true,
2780
+ rails: 1,
2781
+ railSeparation: 0,
2782
+ previewMarkerSize: 115
2783
+ },
2784
+ apron: {
2785
+ subtype: "Double Apron Fence",
2786
+ value: "290304",
2787
+ description: "A wire fence with an apron on each side.",
2788
+ spacing: 1.5,
2789
+ minSpacing: .8,
2790
+ concertina: false,
2791
+ oneSided: false,
2792
+ paired: false,
2793
+ rails: 1,
2794
+ railSeparation: 0,
2795
+ previewMarkerSize: 96
2796
+ },
2797
+ low: {
2798
+ subtype: "Low Wire Fence",
2799
+ value: "290305",
2800
+ description: "A low wire fence obstacle.",
2801
+ spacing: 1.5,
2802
+ minSpacing: .8,
2803
+ concertina: false,
2804
+ oneSided: true,
2805
+ paired: false,
2806
+ rails: 1,
2807
+ railSeparation: 0,
2808
+ previewMarkerSize: 96
2809
+ },
2810
+ high: {
2811
+ subtype: "High Wire Fence",
2812
+ value: "290306",
2813
+ description: "A high wire fence obstacle.",
2814
+ spacing: 1.5,
2815
+ minSpacing: .8,
2816
+ concertina: false,
2817
+ oneSided: true,
2818
+ paired: false,
2819
+ rails: 2,
2820
+ railSeparation: 1,
2821
+ previewMarkerSize: 96
2822
+ },
2823
+ concertina: {
2824
+ subtype: "Single Concertina",
2825
+ value: "290307",
2826
+ description: "A wire obstacle consisting of a single concertina coil.",
2827
+ spacing: 1.25,
2828
+ minSpacing: .8,
2829
+ concertina: true,
2830
+ oneSided: true,
2831
+ paired: false,
2832
+ rails: 1,
2833
+ railSeparation: 0,
2834
+ previewMarkerSize: 96
2835
+ },
2836
+ "double-concertina": {
2837
+ subtype: "Double Strand Concertina",
2838
+ value: "290308",
2839
+ description: "A wire obstacle consisting of double-strand concertina.",
2840
+ spacing: 1.25,
2841
+ minSpacing: .8,
2842
+ concertina: true,
2843
+ oneSided: true,
2844
+ paired: false,
2845
+ rails: 2,
2846
+ railSeparation: .5,
2847
+ previewMarkerSize: 96
2848
+ },
2849
+ "triple-concertina": {
2850
+ subtype: "Triple Strand Concertina",
2851
+ value: "290309",
2852
+ description: "A wire obstacle consisting of triple-strand concertina.",
2853
+ spacing: 1.25,
2854
+ minSpacing: .8,
2855
+ concertina: true,
2856
+ oneSided: true,
2857
+ paired: false,
2858
+ rails: 2,
2859
+ railSeparation: 1,
2860
+ previewMarkerSize: 96
2861
+ }
2862
+ };
2863
+ function createWireObstacle(positions, options, text, context, kind) {
2864
+ const spec = WIRE_KINDS[kind];
2865
+ const projected = positions.map(([x, y]) => project(x, y));
2866
+ const path = smoothLineVerts(projected.filter((point, index) => index === 0 || Math.hypot(point[0] - projected[index - 1][0], point[1] - projected[index - 1][1]) >= 1e-6), options, 16);
2867
+ const { segments, totalLength } = polylineSegments(path);
2868
+ if (totalLength < 1e-6) return {
2869
+ type: "FeatureCollection",
2870
+ features: []
2871
+ };
2872
+ const resolution = normalizeArcResolution(options.resolution);
2873
+ const size = Math.max(EPSILON, options.markerSizePixels !== void 0 && (options.metersPerPixel ?? 0) > 0 ? options.markerSizePixels * options.metersPerPixel : options.markerSize ?? DEFAULT_MARKER_SIZE);
2874
+ const pitch = Math.max(spec.minSpacing, options.markerSpacingRatio ?? spec.spacing) * size;
2875
+ const halfWidth = .4 * size;
2876
+ const pairOffset = spec.paired ? halfWidth : 0;
2877
+ const corners = [];
2878
+ let distance = 0;
2879
+ for (let i = 0; i < segments.length - 1; i++) {
2880
+ const current = segments[i];
2881
+ const next = segments[i + 1];
2882
+ distance += current.length;
2883
+ const dot = current.along[0] * next.along[0] + current.along[1] * next.along[1];
2884
+ if (dot >= .95) continue;
2885
+ const turn = current.along[0] * next.along[1] - current.along[1] * next.along[0];
2886
+ const tangent = Math.sqrt((1 - dot) / Math.max(EPSILON, 1 + dot));
2887
+ const insideTangent = spec.oneSided && turn >= 0 ? 0 : tangent;
2888
+ const clearance = spec.concertina ? size * (insideTangent / 2 + Math.hypot(.25, insideTangent / 2)) : halfWidth + pairOffset + size * (spec.oneSided ? 1 : .5) * insideTangent;
2889
+ corners.push({
2890
+ distance,
2891
+ clearance: Math.max(clearance, pitch / 2)
2892
+ });
2893
+ }
2894
+ const inset = Math.min(totalLength / 2, halfWidth + pairOffset + (spec.rails > 0 ? .25 * size : 0));
2895
+ const centers = [];
2896
+ const spread = (start, end, count) => {
2897
+ for (let i = 0; i < count; i++) centers.push(count === 1 ? (start + end) / 2 : start + i * (end - start) / (count - 1));
2898
+ };
2899
+ if (corners.length === 0) spread(inset, totalLength - inset, Math.max(1, Math.round(totalLength / pitch)));
2900
+ else {
2901
+ let start = inset;
2902
+ for (const corner of [...corners, {
2903
+ distance: totalLength,
2904
+ clearance: inset
2905
+ }]) {
2906
+ const end = corner.distance - corner.clearance;
2907
+ if (end >= start) spread(start, end, Math.max(1, Math.round((end - start) / pitch) + 1));
2908
+ start = corner.distance + corner.clearance;
2909
+ }
2910
+ }
2911
+ const coil = spec.concertina ? Array.from({ length: resolution + 1 }, (_, index) => {
2912
+ const angle = index / resolution * Math.PI * 2;
2913
+ return [.25 * size * Math.cos(angle), -size / 2 + size / 2 * Math.sin(angle)];
2914
+ }) : [];
2915
+ const markers = [];
2916
+ for (const center of centers) for (const offset of spec.paired ? [-pairOffset, pairOffset] : [0]) {
2917
+ const { point, along, perp } = pointAlongPolyline(segments, totalLength, (center + offset) / totalLength);
2918
+ const at = (x, y) => toPosition([point[0] + along[0] * x + perp[0] * y, point[1] + along[1] * x + perp[1] * y]);
2919
+ if (spec.concertina) {
2920
+ const loop = coil.map(([x, y]) => at(x, y));
2921
+ loop[loop.length - 1] = loop[0];
2922
+ markers.push(loop);
2923
+ continue;
2924
+ }
2925
+ const lift = spec.oneSided ? -size / 2 : 0;
2926
+ markers.push([at(-halfWidth, lift - size / 2), at(halfWidth, lift + size / 2)], [at(-halfWidth, lift + size / 2), at(halfWidth, lift - size / 2)]);
2927
+ }
2928
+ const features = [];
2929
+ if (spec.rails > 0) {
2930
+ const coordinates = [path.map(toPosition)];
2931
+ if (spec.rails === 2) {
2932
+ const { right } = offsetPolylineSides(path, path.map(() => spec.railSeparation * size));
2933
+ coordinates.push(right.map(toPosition));
2934
+ }
2935
+ features.push({
2936
+ type: "Feature",
2937
+ properties: { part: "wire" },
2938
+ geometry: {
2939
+ type: "MultiLineString",
2940
+ coordinates
2941
+ }
2942
+ });
2943
+ }
2944
+ features.push({
2945
+ type: "Feature",
2946
+ properties: { part: spec.concertina ? "loops" : "crosses" },
2947
+ geometry: {
2948
+ type: "MultiLineString",
2949
+ coordinates: markers
2950
+ }
2951
+ });
2952
+ const labels = [];
2953
+ pushHostileEndLabels(labels, path, text.N, options, "", context);
2954
+ return {
2955
+ type: "FeatureCollection",
2956
+ features: [...features, ...labels]
2957
+ };
2958
+ }
2959
+ function definition$1(id, name, kind) {
2960
+ const spec = WIRE_KINDS[kind];
2961
+ return defineControlMeasure({
2962
+ metadata: {
2963
+ id,
2964
+ name,
2965
+ description: spec.description,
2966
+ entity: "Protection Lines",
2967
+ entityType: "Wire Obstacles",
2968
+ entitySubtype: spec.subtype,
2969
+ value: spec.value,
2970
+ minCoordinates: 2,
2971
+ geometry: "line",
2972
+ geometryTypes: ["MultiLineString", "Point"],
2973
+ paints: {
2974
+ stroke: true,
2975
+ fill: "none",
2976
+ text: true
2977
+ },
2978
+ drawRule: "Line1",
2979
+ capturesLabelSize: true,
2980
+ labelGeometryUsesResolvedMetrics: ["N"],
2981
+ textAmplifiers: [HOSTILE_LINE_AMPLIFIER],
2982
+ sizePairs: [{
2983
+ id: "cross-size",
2984
+ label: "Marker size",
2985
+ pixels: "markerSizePixels",
2986
+ meters: "markerSize",
2987
+ defaultUnit: "m",
2988
+ rendering: "geometry"
2989
+ }],
2990
+ params: [
2991
+ ...SMOOTH_LINE_PARAMS,
2992
+ ...spec.concertina ? ARC_RESOLUTION_PARAMS : [],
2993
+ ...WIRE_MARKER_PARAMS,
2994
+ {
2995
+ ...WIRE_SPACING_PARAM,
2996
+ min: spec.minSpacing
2997
+ },
2998
+ LABEL_PADDING_PARAM
2999
+ ]
3000
+ },
3001
+ generator: (positions, options = {}, text = {}, context = {}) => createWireObstacle(positions, options, text, context, kind),
3002
+ defaultOptions: {
3003
+ ...spec.concertina ? { resolution: 64 } : {},
3004
+ markerSize: DEFAULT_MARKER_SIZE,
3005
+ markerSizePixels: DEFAULT_MARKER_SIZE_PIXELS,
3006
+ markerSpacingRatio: spec.spacing,
3007
+ smooth: false,
3008
+ smoothResolution: 16
3009
+ },
3010
+ rule: line1DrawRule,
3011
+ previewSample: {
3012
+ controlPoints: [[1, 0], [-1, 0]],
3013
+ options: { markerSize: spec.previewMarkerSize }
3014
+ }
3015
+ });
3016
+ }
3017
+ const WIRE_OBSTACLE_UNSPECIFIED = definition$1("wire-obstacle-unspecified", "Wire Obstacles – Unspecified", "unspecified");
3018
+ const SINGLE_FENCE = definition$1("single-fence", "Single Fence", "single");
3019
+ const DOUBLE_FENCE = definition$1("double-fence", "Double Fence", "double");
3020
+ const DOUBLE_APRON_FENCE = definition$1("double-apron-fence", "Double Apron Fence", "apron");
3021
+ const LOW_WIRE_FENCE = definition$1("low-wire-fence", "Low Wire Fence", "low");
3022
+ const HIGH_WIRE_FENCE = definition$1("high-wire-fence", "High Wire Fence", "high");
3023
+ const SINGLE_CONCERTINA = definition$1("single-concertina", "Single Concertina", "concertina");
3024
+ const DOUBLE_STRAND_CONCERTINA = definition$1("double-strand-concertina", "Double Strand Concertina", "double-concertina");
3025
+ const TRIPLE_STRAND_CONCERTINA = definition$1("triple-strand-concertina", "Triple Strand Concertina", "triple-concertina");
2624
3026
  //#endregion
2625
3027
  //#region src/generators/cm34-mission-tasks/shared.ts
2626
3028
  /**
@@ -6467,78 +6869,6 @@ const ASSEMBLY_AREA = defineControlMeasure({
6467
6869
  }
6468
6870
  });
6469
6871
  //#endregion
6470
- //#region src/generators/cm29-protection-lines/params.ts
6471
- const FORTIFIED_PARAMS = [
6472
- ...SMOOTH_LINE_PARAMS,
6473
- {
6474
- key: "toothSizePixels",
6475
- label: "Tooth size",
6476
- description: "Side length of the square crenellations",
6477
- type: "number",
6478
- min: 5,
6479
- max: 50,
6480
- step: 1,
6481
- unit: "px"
6482
- },
6483
- {
6484
- key: "toothSize",
6485
- label: "Tooth size",
6486
- description: "Side length of the square crenellations",
6487
- type: "number",
6488
- min: 1,
6489
- max: 500,
6490
- step: 1,
6491
- unit: "m"
6492
- },
6493
- LABEL_PADDING_PARAM
6494
- ];
6495
- const ANTITANK_DITCH_PARAMS = [
6496
- ...SMOOTH_LINE_PARAMS,
6497
- {
6498
- key: "toothHeightPixels",
6499
- label: "Tooth height",
6500
- description: "Perpendicular depth of each triangular tooth",
6501
- type: "number",
6502
- min: 5,
6503
- max: 50,
6504
- step: 1,
6505
- unit: "px"
6506
- },
6507
- {
6508
- key: "toothHeight",
6509
- label: "Tooth height",
6510
- description: "Perpendicular depth of each triangular tooth",
6511
- type: "number",
6512
- min: 1,
6513
- max: 500,
6514
- step: 1,
6515
- unit: "m"
6516
- },
6517
- {
6518
- key: "toothWidthRatio",
6519
- presentationTier: "advanced",
6520
- label: "Tooth width ratio",
6521
- description: "Tooth base span as a multiple of height",
6522
- type: "number",
6523
- min: .5,
6524
- max: 3,
6525
- step: .05,
6526
- unit: "x"
6527
- },
6528
- LABEL_PADDING_PARAM
6529
- ];
6530
- const ANTITANK_WALL_PARAMS = [...ANTITANK_DITCH_PARAMS, {
6531
- key: "toothSpacingRatio",
6532
- presentationTier: "advanced",
6533
- label: "Tooth spacing ratio",
6534
- description: "Gap between teeth as a multiple of base width",
6535
- type: "number",
6536
- min: 0,
6537
- max: 3,
6538
- step: .05,
6539
- unit: "x"
6540
- }];
6541
- //#endregion
6542
6872
  //#region src/generators/cm29-protection-lines/antitankDitch.ts
6543
6873
  const DEFAULT_TOOTH_HEIGHT = 50;
6544
6874
  const DEFAULT_TOOTH_HEIGHT_PIXELS = 10;
@@ -9571,20 +9901,6 @@ function normalizeSmoothResolution(value) {
9571
9901
  if (!Number.isFinite(value)) return DEFAULT_SMOOTH_RESOLUTION$3;
9572
9902
  return Math.min(MAX_SMOOTH_RESOLUTION, Math.max(MIN_SMOOTH_RESOLUTION, Math.round(value)));
9573
9903
  }
9574
- function normalizeArcResolution(value) {
9575
- if (typeof value !== "number" || !Number.isFinite(value)) return 64;
9576
- return Math.min(360, Math.max(4, Math.round(value)));
9577
- }
9578
- const ARC_RESOLUTION_PARAMS = [{
9579
- key: "resolution",
9580
- presentationTier: "advanced",
9581
- label: "Resolution",
9582
- description: "Number of segments in a full 360° sweep.",
9583
- type: "number",
9584
- min: 4,
9585
- max: 360,
9586
- step: 1
9587
- }];
9588
9904
  //#endregion
9589
9905
  //#region src/generators/cm99-generic-graphics/params.ts
9590
9906
  const SMOOTH_PATH_PARAMS = [{
@@ -11435,7 +11751,7 @@ function createSecurityTaskSymbol(coordinates, config, options = {}) {
11435
11751
  ...options
11436
11752
  };
11437
11753
  const arrowOptions = resolveTacticalArrowOptions(resolved);
11438
- const lines = [createTacticalArrow(p2, p1, p3, arrowOptions), createTacticalArrow(p3, p4, p2, arrowOptions)].flatMap((arrow) => arrow ?? []);
11754
+ const lines = [createTacticalArrow(p2, p1, arrowOptions, -1), createTacticalArrow(p3, p4, arrowOptions, 1)].flatMap((arrow) => arrow ?? []);
11439
11755
  if (lines.length === 0) return {
11440
11756
  type: "FeatureCollection",
11441
11757
  features: []
@@ -11465,13 +11781,12 @@ function createSecurityTaskSymbol(coordinates, config, options = {}) {
11465
11781
  };
11466
11782
  }
11467
11783
  /** A Search Area-style lightning shaft with a Principal Direction of Fire open head. */
11468
- function createTacticalArrow(origin, tip, opposite, options) {
11784
+ function createTacticalArrow(origin, tip, options, bendSide) {
11469
11785
  const leg = vecSub(tip, origin);
11470
11786
  const totalLegLength = vecMag(leg);
11471
11787
  if (totalLegLength < 1e-6) return void 0;
11472
11788
  const legDirection = vecNorm(leg);
11473
- let normal = [-legDirection[1], legDirection[0]];
11474
- if (vecDot(normal, vecSub(opposite, origin)) > 0) normal = vecScale(normal, -1);
11789
+ const normal = [-legDirection[1] * bendSide, legDirection[0] * bendSide];
11475
11790
  const amplitude = totalLegLength * options.zigzagAmplitudeRatio;
11476
11791
  const zigzagPointA = vecAdd(vecAdd(origin, vecScale(leg, options.zigzagStart)), vecScale(normal, amplitude));
11477
11792
  const zigzagPointB = vecAdd(vecAdd(origin, vecScale(leg, options.zigzagEnd)), vecScale(normal, -amplitude));
@@ -17337,6 +17652,206 @@ const MINEFIELD = defineControlMeasure({
17337
17652
  }
17338
17653
  });
17339
17654
  //#endregion
17655
+ //#region src/generators/cm27-protection-areas/obstacle-areas.ts
17656
+ const DEFAULT_OBSTACLE_AREA_OPTIONS = {
17657
+ toothSize: 50,
17658
+ toothSizePixels: 10,
17659
+ smooth: false,
17660
+ smoothResolution: 16
17661
+ };
17662
+ /** Preserve control-point corners and keep tooth direction independent of winding. */
17663
+ function toothedRing(ring, size, inward) {
17664
+ const side = (ringSignedArea2(ring) >= 0 ? -1 : 1) * (inward ? -1 : 1);
17665
+ const width = size * (inward ? 1 : .8);
17666
+ const pitch = size * (inward ? 2.4 : 1.6);
17667
+ const result = [ring[0]];
17668
+ for (let i = 1; i < ring.length; i++) {
17669
+ const a = ring[i - 1];
17670
+ const b = ring[i];
17671
+ const dx = b[0] - a[0];
17672
+ const dy = b[1] - a[1];
17673
+ const length = Math.hypot(dx, dy);
17674
+ if (length < 1e-6) continue;
17675
+ const margin = inward ? Math.min(length / 4, .75 * size) : 0;
17676
+ const available = length - 2 * margin;
17677
+ const count = Math.max(1, Math.round(available / pitch));
17678
+ const fittedWidth = Math.min(width, available / count);
17679
+ const offsets = [
17680
+ -fittedWidth / 2,
17681
+ 0,
17682
+ fittedWidth / 2
17683
+ ];
17684
+ for (let tooth = 0; tooth < count; tooth++) {
17685
+ const center = margin + (tooth + .5) / count * available;
17686
+ for (const offset of offsets) {
17687
+ const t = (center + offset) / length;
17688
+ const height = offset === 0 ? side * size : 0;
17689
+ result.push([a[0] + dx * t - dy / length * height, a[1] + dy * t + dx / length * height]);
17690
+ }
17691
+ }
17692
+ result.push(b);
17693
+ }
17694
+ result[result.length - 1] = result[0];
17695
+ return result;
17696
+ }
17697
+ const OBSTACLE_AREA_KINDS = {
17698
+ belt: {
17699
+ inward: false,
17700
+ previewToothSize: 170,
17701
+ description: "A brigade-level control measure within an obstacle zone that limits friendly obstacle employment and focuses the defense."
17702
+ },
17703
+ zone: {
17704
+ inward: false,
17705
+ previewToothSize: 140,
17706
+ description: "A division-level control measure designating land areas where subordinate units are authorized to employ tactical obstacles."
17707
+ },
17708
+ free: {
17709
+ inward: true,
17710
+ previewToothSize: 130,
17711
+ description: "An area designated to remain completely free of reinforcing obstacles."
17712
+ },
17713
+ restricted: {
17714
+ inward: true,
17715
+ previewToothSize: 130,
17716
+ description: "A control measure limiting the types or number of obstacles permitted within an area."
17717
+ }
17718
+ };
17719
+ function createObstacleArea(positions, options, text, context, kind) {
17720
+ const ring = buildClosedRing(positions, options.smooth ?? false, options.smoothResolution ?? 16, 16);
17721
+ const size = calculateAntitankDitchHeight({
17722
+ toothHeight: options.toothSize,
17723
+ toothHeightPixels: options.toothSizePixels,
17724
+ metersPerPixel: options.metersPerPixel
17725
+ });
17726
+ const { inward } = OBSTACLE_AREA_KINDS[kind];
17727
+ const boundary = toothedRing(options.smooth ? evenlySpacePath(ring, inward ? 8 * size : 4 * size) : ring, size, inward);
17728
+ const labels = [];
17729
+ const [cx, cy] = ringLabelAnchor(ring);
17730
+ const hasWindow = inward && Boolean(text.W || text.W1);
17731
+ const rows = Number(kind === "free") + Number(Boolean(text.T)) + Number(hasWindow);
17732
+ const pitch = resolveLabelOffsetMeters(options, 1.2 + Math.max(0, options.labelPadding ?? 0));
17733
+ let row = 0;
17734
+ const rowY = () => cy + ((rows - 1) / 2 - row++) * pitch;
17735
+ const sizeProps = labelSizeProps(options);
17736
+ const addLabel = (x, y, value, props = {}) => {
17737
+ pushLabel(labels, [x, y], value, HORIZONTAL_LABEL_ROTATION, sizeProps, props.anchor, props.field, props.key);
17738
+ if (props.labelPlacement === false) labels[labels.length - 1].properties.labelPlacement = false;
17739
+ };
17740
+ if (kind === "free") addLabel(cx, rowY(), "FREE", { key: "label:free" });
17741
+ if (text.T) addLabel(cx, rowY(), text.T, { field: "T" });
17742
+ if (hasWindow) {
17743
+ const y = rowY();
17744
+ if (text.W && text.W1) {
17745
+ const gap = resolveLabelOffsetMeters(options, 1.8);
17746
+ addLabel(cx - gap, y, text.W, {
17747
+ field: "W",
17748
+ anchor: "end"
17749
+ });
17750
+ addLabel(cx, y, "–", { labelPlacement: false });
17751
+ addLabel(cx + gap, y, text.W1, {
17752
+ field: "W1",
17753
+ anchor: "start"
17754
+ });
17755
+ } else if (text.W) addLabel(cx, y, text.W, { field: "W" });
17756
+ else if (text.W1) addLabel(cx, y, text.W1, { field: "W1" });
17757
+ }
17758
+ const gaps = pushAreaLabels(labels, ring, { hostile: text.N }, options, context.amplifierPlacements, {
17759
+ ringVerts: boundary,
17760
+ extraClearanceMeters: size
17761
+ }, context);
17762
+ if (kind === "restricted") for (const label of labels) label.properties.textBackground = true;
17763
+ return {
17764
+ type: "FeatureCollection",
17765
+ features: [...kind === "restricted" ? patternedAreaFeatures(boundary, gaps, "reverse-hatch") : [boundaryFeature(boundary, gaps)], ...labels]
17766
+ };
17767
+ }
17768
+ const COMMON_METADATA$1 = {
17769
+ entity: "Protection Areas",
17770
+ minCoordinates: 3,
17771
+ geometry: "area",
17772
+ geometryTypes: [
17773
+ "Polygon",
17774
+ "MultiLineString",
17775
+ "Point"
17776
+ ],
17777
+ drawRule: "Area1",
17778
+ capturesLabelSize: true,
17779
+ labelGeometryUsesResolvedMetrics: ["N"],
17780
+ sizePairs: [TOOTH_SIZE_SIZE_PAIR],
17781
+ params: [
17782
+ {
17783
+ key: "toothSize",
17784
+ label: "Tooth size",
17785
+ description: "Boundary tooth height in meters",
17786
+ type: "number",
17787
+ min: 1,
17788
+ max: 500,
17789
+ step: 1,
17790
+ unit: "m"
17791
+ },
17792
+ {
17793
+ key: "toothSizePixels",
17794
+ label: "Tooth size",
17795
+ description: "Boundary tooth height in pixels",
17796
+ type: "number",
17797
+ min: 1,
17798
+ max: 50,
17799
+ step: 1,
17800
+ unit: "px"
17801
+ },
17802
+ ...AREA_SMOOTH_PARAMS,
17803
+ AREA_LABEL_PADDING_PARAM
17804
+ ]
17805
+ };
17806
+ function definition(id, name, value, kind) {
17807
+ const { inward, previewToothSize, description } = OBSTACLE_AREA_KINDS[kind];
17808
+ return defineControlMeasure({
17809
+ metadata: {
17810
+ ...COMMON_METADATA$1,
17811
+ id,
17812
+ name,
17813
+ value,
17814
+ entityType: name,
17815
+ description,
17816
+ paints: {
17817
+ stroke: true,
17818
+ fill: kind === "restricted" ? "fixed" : "none",
17819
+ text: true
17820
+ },
17821
+ textAmplifiers: inward ? AREA_TEXT_AMPLIFIERS_NO_ADDITIONAL_INFO : AREA_TEXT_AMPLIFIERS_DESIGNATION_HOSTILE
17822
+ },
17823
+ generator: (positions, options = {}, text = {}, context = {}) => createObstacleArea(positions, options, text, context, kind),
17824
+ defaultOptions: DEFAULT_OBSTACLE_AREA_OPTIONS,
17825
+ rule: area1DrawRule,
17826
+ previewSample: {
17827
+ controlPoints: kind === "belt" ? [
17828
+ [-1, -.5],
17829
+ [1, -.5],
17830
+ [1, .5],
17831
+ [-1, .5]
17832
+ ] : [
17833
+ [-1, -.7],
17834
+ [1, -.7],
17835
+ [.95, .25],
17836
+ [-1, .8]
17837
+ ],
17838
+ options: {
17839
+ toothSize: previewToothSize,
17840
+ labelSize: inward ? 70 : 96
17841
+ },
17842
+ textAmplifiers: inward ? {
17843
+ T: "T",
17844
+ W: "W",
17845
+ W1: "W1"
17846
+ } : { T: "T" }
17847
+ }
17848
+ });
17849
+ }
17850
+ const OBSTACLE_BELT = definition("obstacle-belt", "Obstacle Belt", "270100", "belt");
17851
+ const OBSTACLE_ZONE = definition("obstacle-zone", "Obstacle Zone", "270200", "zone");
17852
+ const OBSTACLE_FREE_ZONE = definition("obstacle-free-zone", "Obstacle Free Zone", "270300", "free");
17853
+ const OBSTACLE_RESTRICTED_ZONE = definition("obstacle-restricted-zone", "Obstacle Restricted Zone", "270400", "restricted");
17854
+ //#endregion
17340
17855
  //#region src/generators/cm27-protection-areas/mine-areas.ts
17341
17856
  const DEFAULT_MINE_AREA_OPTIONS = {
17342
17857
  mineType: "unspecified",
@@ -18353,14 +18868,12 @@ function createSearchArea(coordinates, options = {}) {
18353
18868
  ];
18354
18869
  const shaftSegments = [];
18355
18870
  const headPolygons = [];
18356
- const addLeg = (origin, tip, opposite) => {
18871
+ const addLeg = (origin, tip, bendSide) => {
18357
18872
  const v = vecSub(tip, origin);
18358
18873
  const totalLen = vecMag(v);
18359
18874
  if (totalLen < 1e-6) return;
18360
18875
  const u = vecNorm(v);
18361
- let n = [-u[1], u[0]];
18362
- const toOpp = vecSub(opposite, origin);
18363
- if (vecDot(n, toOpp) > 0) n = vecScale(n, -1);
18876
+ const n = [-u[1] * bendSide, u[0] * bendSide];
18364
18877
  const offset = totalLen * safeZigzagAmplitudeRatio;
18365
18878
  const ptA = vecAdd(vecAdd(origin, vecScale(v, safeZigzagStart)), vecScale(n, offset));
18366
18879
  const ptB = vecAdd(vecAdd(origin, vecScale(v, safeZigzagEnd)), vecScale(n, -offset));
@@ -18387,8 +18900,8 @@ function createSearchArea(coordinates, options = {}) {
18387
18900
  tip
18388
18901
  ].map((p) => unproject(p[0], p[1]))]);
18389
18902
  };
18390
- addLeg(p1, p2, p3);
18391
- addLeg(p1, p3, p2);
18903
+ addLeg(p1, p2, 1);
18904
+ addLeg(p1, p3, -1);
18392
18905
  const features = [];
18393
18906
  if (shaftSegments.length > 0) features.push({
18394
18907
  type: "Feature",
@@ -19109,6 +19622,10 @@ const DEFINITIONS = {
19109
19622
  "no-fire-area-irregular": NO_FIRE_AREA_IRREGULAR,
19110
19623
  "minefield-dynamic": DYNAMIC_MINEFIELD,
19111
19624
  "mined-area": MINED_AREA,
19625
+ "obstacle-belt": OBSTACLE_BELT,
19626
+ "obstacle-zone": OBSTACLE_ZONE,
19627
+ "obstacle-free-zone": OBSTACLE_FREE_ZONE,
19628
+ "obstacle-restricted-zone": OBSTACLE_RESTRICTED_ZONE,
19112
19629
  "pickup-zone": PICKUP_ZONE,
19113
19630
  "assault-position": ASSAULT_POSITION,
19114
19631
  "attack-position": ATTACK_POSITION,
@@ -19193,6 +19710,15 @@ const DEFINITIONS = {
19193
19710
  "antitank-ditch-under-construction": ANTITANK_DITCH_UNDER_CONSTRUCTION,
19194
19711
  "antitank-ditch-completed": ANTITANK_DITCH_COMPLETED,
19195
19712
  "antitank-wall": ANTITANK_WALL,
19713
+ "wire-obstacle-unspecified": WIRE_OBSTACLE_UNSPECIFIED,
19714
+ "single-fence": SINGLE_FENCE,
19715
+ "double-fence": DOUBLE_FENCE,
19716
+ "double-apron-fence": DOUBLE_APRON_FENCE,
19717
+ "low-wire-fence": LOW_WIRE_FENCE,
19718
+ "high-wire-fence": HIGH_WIRE_FENCE,
19719
+ "single-concertina": SINGLE_CONCERTINA,
19720
+ "double-strand-concertina": DOUBLE_STRAND_CONCERTINA,
19721
+ "triple-strand-concertina": TRIPLE_STRAND_CONCERTINA,
19196
19722
  "fortified-line": FORTIFIED_LINE,
19197
19723
  "fortified-area": FORTIFIED_AREA,
19198
19724
  "frontal-attack": FRONTAL_ATTACK,
@@ -19623,4 +20149,4 @@ function assertNever(value) {
19623
20149
  throw new Error(`Unhandled control measure kind: ${String(value)}`);
19624
20150
  }
19625
20151
  //#endregion
19626
- export { DEFAULT_PHASE_LINE_OPTIONS as $, DEFAULT_LABEL_SIZE_CLAMP_CSS_PIXELS as $n, DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS as $t, DEFAULT_SECURE_OPTIONS as A, secureDrawRule as An, DEFAULT_GENERIC_CIRCLE_OPTIONS as At, DEFAULT_FORTIFIED_LINE_OPTIONS as B, getMidpointPerpendicularSignedDistance as Bn, DEFAULT_BLOCK_ARROW_OPTIONS as Bt, DEFAULT_LANDING_ZONE_OPTIONS as C, line1DrawRule as Cn, RADAR_SEARCH_DOCTRINE_FILL_COLOR as Ct, DEFAULT_WITHDRAW_OPTIONS as D, sectorDrawRule as Dn, DEFAULT_GENERIC_RECTANGLE_OPTIONS as Dt, DEFAULT_WITHDRAW_UNDER_PRESSURE_OPTIONS as E, dynamicPointDrawRule as En, DEFAULT_GENERIC_SECTOR_OPTIONS as Et, DEFAULT_PENETRATE_OPTIONS as F, centerRadiusDrawRule as Fn, DEFAULT_BLOCK_MISSION_TASK_OPTIONS as Ft, DEFAULT_LIMIT_OF_ADVANCE_OPTIONS as G, project as Gn, DEFAULT_ATTACK_BY_FIRE_OPTIONS as Gt, PROBABLE_LINE_OF_DEPLOYMENT_DASH as H, snapToMidpointPerpendicular as Hn, DEFAULT_CONTAIN_OPTIONS as Ht, DEFAULT_OCCUPY_OPTIONS as I, containDrawRule as In, DEFAULT_GENERIC_C2_LINE_OPTIONS as It, DEFAULT_FORWARD_EDGE_OF_BATTLE_AREA_OPTIONS as J, EPSILON as Jn, DEFAULT_ASSEMBLY_AREA_OPTIONS as Jt, DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS as K, sphericalBearing as Kn, DEFAULT_ANTITANK_WALL_OPTIONS as Kt, DEFAULT_MOVEMENT_TO_CONTACT_OPTIONS as L, area27DrawRule as Ln, DEFAULT_ENGINEER_WORK_LINE_OPTIONS as Lt, DEFAULT_RETIRE_OPTIONS as M, occupyDrawRule as Mn, DEFAULT_CANALIZE_OPTIONS as Mt, DEFAULT_RELIEF_IN_PLACE_OPTIONS as N, disruptDrawRule as Nn, DEFAULT_BYPASS_OPTIONS as Nt, DEFAULT_EVACUATE_OPTIONS as O, staticPointDrawRule as On, DEFAULT_GENERIC_POLYGON_OPTIONS as Ot, DEFAULT_REARWARD_PASSAGE_OF_LINES_OPTIONS as P, blockDrawRule as Pn, DEFAULT_BREACH_OPTIONS as Pt, DEFAULT_BRIDGEHEAD_LINE_OPTIONS as Q, DEFAULT_LABEL_HEIGHT_CSS_PIXELS as Qn, DEFAULT_AREA_DEFENSE_OPTIONS as Qt, DEFAULT_FRONTAL_ATTACK_OPTIONS as R, computeDefaultMidpointPerpendicularPoint as Rn, DEFAULT_LIGHT_LINE_OPTIONS as Rt, DEFAULT_MAIN_ATTACK_OPTIONS as S, turnDrawRule as Sn, DEFAULT_RADAR_SEARCH_DOCTRINE_OPTIONS as St, DEFAULT_TURN_OPTIONS as T, attackByFireDrawRule as Tn, DEFAULT_GENERIC_TEXT_OPTIONS as Tt, DEFAULT_LINE_OF_DEPARTURE_CONTACT_OPTIONS as U, createBaselineFrame as Un, DEFAULT_BATTLE_POSITION_OPTIONS as Ut, DEFAULT_PROBABLE_LINE_OF_DEPLOYMENT_OPTIONS as V, pointOnMidpointPerpendicularAxis as Vn, DEFAULT_BLOCK_OPTIONS as Vt, DEFAULT_LINE_OF_DEPARTURE_OPTIONS as W, haversineDistance as Wn, DEFAULT_ATTACK_HELICOPTER_OPTIONS as Wt, DEFAULT_HOLDING_LINE_OPTIONS as X, isFiniteNumber as Xn, DEFAULT_MOBILE_DEFENSE_OPTIONS as Xt, DEFAULT_RELEASE_LINE_OPTIONS as Y, getMetersPerPixel as Yn, DEFAULT_AREA_OF_OPERATIONS_OPTIONS as Yt, DEFAULT_INFILTRATION_LANE_OPTIONS as Z, roundToFixed as Zn, DEFAULT_ENGAGEMENT_AREA_OPTIONS as Zt, DEFAULT_PICKUP_ZONE_OPTIONS as _, polyline1DrawRule as _n, DEFAULT_SUPPORTING_ATTACK_OPTIONS as _t, DEFINITIONS as a, resolveAmplifierPlacement as an, DEFAULT_SYMBOL_COLOR as ar, DEFAULT_DISRUPT_OPTIONS as at, DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS as b, line24DrawRule as bn, DEFAULT_ISOLATE_OPTIONS as bt, getDefaultOptions as c, DEFAULT_DESTROY_OPTIONS as cn, createFollowAndAssume as ct, DEFAULT_SUPPORT_BY_FIRE_OPTIONS as d, DEFAULT_DEFEAT_OPTIONS as dn, DEFAULT_DEMONSTRATE_OPTIONS as dt, DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS as en, DEFAULT_LINE_CAP as er, DEFAULT_FLOT_OPTIONS as et, DEFAULT_RETAIN_OPTIONS as f, rectangleDrawRule as fn, DEFAULT_DELAY_OPTIONS as ft, DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS as g, supportByFireDrawRule as gn, DEFAULT_COUNTERATTACK_OPTIONS as gt, SECONDARY_DIRECTION_OF_FIRE_DASH as h, computeInitialWidthPoint as hn, DEFAULT_COUNTERATTACK_BY_FIRE_OPTIONS as ht, CONTROL_MEASURE_METADATA as i, normalizeTextAmplifiers as in, DEFAULT_STROKE_WIDTH_CSS_PIXELS as ir, DEFAULT_ENCIRCLEMENT_OPTIONS as it, DEFAULT_SCREEN_OPTIONS as j, penetrateDrawRule as jn, DEFAULT_CLASSIC_ARROW_OPTIONS as jt, DEFAULT_SEIZE_OPTIONS as k, point12DrawRule as kn, DEFAULT_GENERIC_LINE_OPTIONS as kt, listControlMeasureMetadata as l, DEFAULT_NEUTRALIZE_OPTIONS as ln, DEFAULT_DISRUPT_MISSION_TASK_OPTIONS as lt, DEFAULT_SECONDARY_DIRECTION_OF_FIRE_OPTIONS as m, calculateMetrics as mn, DEFAULT_TACTICAL_ARROW_OPTIONS as mt, resolveStyleHints as n, TEXT_AMPLIFIER_FIELDS as nn, DEFAULT_PORTRAYAL as nr, DEFAULT_FIX_OPTIONS as nt, getControlMeasureMetadata as o, DEFAULT_AMBUSH_OPTIONS as on, DEFAULT_GUARD_OPTIONS as ot, DEFAULT_STRONG_POINT_OPTIONS as p, axis1DrawRule as pn, DEFAULT_COVER_OPTIONS as pt, DEFAULT_HANDOVER_LINE_OPTIONS as q, unproject as qn, DEFAULT_ANTITANK_DITCH_OPTIONS as qt, CONTROL_MEASURE_IDS as r, canonicalTextAmplifierKey as rn, DEFAULT_STROKE_DASH_CSS_PIXELS as rr, DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS as rt, getControlMeasureMetadataByValue as s, DEFAULT_AIRBORNE_ATTACK_OPTIONS as sn, createFollowAndSupport as st, renderControlMeasure as t, DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS as tn, DEFAULT_LINE_JOIN as tr, DEFAULT_FIX_MISSION_TASK_OPTIONS as tt, DEFAULT_TURNING_MOVEMENT_OPTIONS as u, DEFAULT_SUPPRESS_OPTIONS as un, DEFAULT_DISENGAGE_OPTIONS as ut, DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS as v, line27DrawRule as vn, DEFAULT_CORDON_AND_SEARCH_OPTIONS as vt, DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS as w, ambushDrawRule as wn, RADAR_SEARCH_DOCTRINE_STROKE_COLOR as wt, DEFAULT_MINEFIELD_OPTIONS as x, line23DrawRule as xn, DEFAULT_CLEAR_OPTIONS as xt, DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS as y, line26DrawRule as yn, DEFAULT_CORDON_AND_KNOCK_OPTIONS as yt, DEFAULT_FORTIFIED_AREA_OPTIONS as z, createMidpointPerpendicularDrawRule as zn, DEFAULT_BOUNDARY_OPTIONS as zt };
20152
+ export { DEFAULT_PHASE_LINE_OPTIONS as $, project as $n, DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS as $t, DEFAULT_SECURE_OPTIONS as A, turnDrawRule as An, DEFAULT_GENERIC_CIRCLE_OPTIONS as At, DEFAULT_FORTIFIED_LINE_OPTIONS as B, occupyDrawRule as Bn, DEFAULT_BLOCK_ARROW_OPTIONS as Bt, DEFAULT_LANDING_ZONE_OPTIONS as C, computeInitialWidthPoint as Cn, RADAR_SEARCH_DOCTRINE_FILL_COLOR as Ct, DEFAULT_WITHDRAW_OPTIONS as D, line26DrawRule as Dn, DEFAULT_GENERIC_RECTANGLE_OPTIONS as Dt, DEFAULT_WITHDRAW_UNDER_PRESSURE_OPTIONS as E, line27DrawRule as En, DEFAULT_GENERIC_SECTOR_OPTIONS as Et, DEFAULT_PENETRATE_OPTIONS as F, sectorDrawRule as Fn, DEFAULT_BLOCK_MISSION_TASK_OPTIONS as Ft, DEFAULT_LIMIT_OF_ADVANCE_OPTIONS as G, area27DrawRule as Gn, DEFAULT_ATTACK_BY_FIRE_OPTIONS as Gt, PROBABLE_LINE_OF_DEPLOYMENT_DASH as H, blockDrawRule as Hn, DEFAULT_CONTAIN_OPTIONS as Ht, DEFAULT_OCCUPY_OPTIONS as I, staticPointDrawRule as In, DEFAULT_GENERIC_C2_LINE_OPTIONS as It, DEFAULT_FORWARD_EDGE_OF_BATTLE_AREA_OPTIONS as J, getMidpointPerpendicularSignedDistance as Jn, DEFAULT_ASSEMBLY_AREA_OPTIONS as Jt, DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS as K, computeDefaultMidpointPerpendicularPoint as Kn, DEFAULT_ANTITANK_WALL_OPTIONS as Kt, DEFAULT_MOVEMENT_TO_CONTACT_OPTIONS as L, point12DrawRule as Ln, DEFAULT_ENGINEER_WORK_LINE_OPTIONS as Lt, DEFAULT_RETIRE_OPTIONS as M, ambushDrawRule as Mn, DEFAULT_CANALIZE_OPTIONS as Mt, DEFAULT_RELIEF_IN_PLACE_OPTIONS as N, attackByFireDrawRule as Nn, DEFAULT_BYPASS_OPTIONS as Nt, DEFAULT_EVACUATE_OPTIONS as O, line24DrawRule as On, DEFAULT_GENERIC_POLYGON_OPTIONS as Ot, DEFAULT_REARWARD_PASSAGE_OF_LINES_OPTIONS as P, dynamicPointDrawRule as Pn, DEFAULT_BREACH_OPTIONS as Pt, DEFAULT_BRIDGEHEAD_LINE_OPTIONS as Q, haversineDistance as Qn, DEFAULT_AREA_DEFENSE_OPTIONS as Qt, DEFAULT_FRONTAL_ATTACK_OPTIONS as R, secureDrawRule as Rn, DEFAULT_LIGHT_LINE_OPTIONS as Rt, DEFAULT_MAIN_ATTACK_OPTIONS as S, calculateMetrics as Sn, DEFAULT_RADAR_SEARCH_DOCTRINE_OPTIONS as St, DEFAULT_TURN_OPTIONS as T, polyline1DrawRule as Tn, DEFAULT_GENERIC_TEXT_OPTIONS as Tt, DEFAULT_LINE_OF_DEPARTURE_CONTACT_OPTIONS as U, centerRadiusDrawRule as Un, DEFAULT_BATTLE_POSITION_OPTIONS as Ut, DEFAULT_PROBABLE_LINE_OF_DEPLOYMENT_OPTIONS as V, disruptDrawRule as Vn, DEFAULT_BLOCK_OPTIONS as Vt, DEFAULT_LINE_OF_DEPARTURE_OPTIONS as W, containDrawRule as Wn, DEFAULT_ATTACK_HELICOPTER_OPTIONS as Wt, DEFAULT_HOLDING_LINE_OPTIONS as X, snapToMidpointPerpendicular as Xn, DEFAULT_MOBILE_DEFENSE_OPTIONS as Xt, DEFAULT_RELEASE_LINE_OPTIONS as Y, pointOnMidpointPerpendicularAxis as Yn, DEFAULT_AREA_OF_OPERATIONS_OPTIONS as Yt, DEFAULT_INFILTRATION_LANE_OPTIONS as Z, createBaselineFrame as Zn, DEFAULT_ENGAGEMENT_AREA_OPTIONS as Zt, DEFAULT_PICKUP_ZONE_OPTIONS as _, DEFAULT_STROKE_DASH_CSS_PIXELS as _n, DEFAULT_SUPPORTING_ATTACK_OPTIONS as _t, DEFINITIONS as a, resolveAmplifierPlacement as an, roundToFixed as ar, DEFAULT_DISRUPT_OPTIONS as at, DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS as b, rectangleDrawRule as bn, DEFAULT_ISOLATE_OPTIONS as bt, getDefaultOptions as c, DEFAULT_DESTROY_OPTIONS as cn, createFollowAndAssume as ct, DEFAULT_SUPPORT_BY_FIRE_OPTIONS as d, DEFAULT_DEFEAT_OPTIONS as dn, DEFAULT_DEMONSTRATE_OPTIONS as dt, DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS as en, sphericalBearing as er, DEFAULT_FLOT_OPTIONS as et, DEFAULT_RETAIN_OPTIONS as f, DEFAULT_LABEL_HEIGHT_CSS_PIXELS as fn, DEFAULT_DELAY_OPTIONS as ft, DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS as g, DEFAULT_PORTRAYAL as gn, DEFAULT_COUNTERATTACK_OPTIONS as gt, SECONDARY_DIRECTION_OF_FIRE_DASH as h, DEFAULT_LINE_JOIN as hn, DEFAULT_COUNTERATTACK_BY_FIRE_OPTIONS as ht, CONTROL_MEASURE_METADATA as i, normalizeTextAmplifiers as in, isFiniteNumber as ir, DEFAULT_ENCIRCLEMENT_OPTIONS as it, DEFAULT_SCREEN_OPTIONS as j, line1DrawRule as jn, DEFAULT_CLASSIC_ARROW_OPTIONS as jt, DEFAULT_SEIZE_OPTIONS as k, line23DrawRule as kn, DEFAULT_GENERIC_LINE_OPTIONS as kt, listControlMeasureMetadata as l, DEFAULT_NEUTRALIZE_OPTIONS as ln, DEFAULT_DISRUPT_MISSION_TASK_OPTIONS as lt, DEFAULT_SECONDARY_DIRECTION_OF_FIRE_OPTIONS as m, DEFAULT_LINE_CAP as mn, DEFAULT_TACTICAL_ARROW_OPTIONS as mt, resolveStyleHints as n, TEXT_AMPLIFIER_FIELDS as nn, EPSILON as nr, DEFAULT_FIX_OPTIONS as nt, getControlMeasureMetadata as o, DEFAULT_AMBUSH_OPTIONS as on, DEFAULT_GUARD_OPTIONS as ot, DEFAULT_STRONG_POINT_OPTIONS as p, DEFAULT_LABEL_SIZE_CLAMP_CSS_PIXELS as pn, DEFAULT_COVER_OPTIONS as pt, DEFAULT_HANDOVER_LINE_OPTIONS as q, createMidpointPerpendicularDrawRule as qn, DEFAULT_ANTITANK_DITCH_OPTIONS as qt, CONTROL_MEASURE_IDS as r, canonicalTextAmplifierKey as rn, getMetersPerPixel as rr, DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS as rt, getControlMeasureMetadataByValue as s, DEFAULT_AIRBORNE_ATTACK_OPTIONS as sn, createFollowAndSupport as st, renderControlMeasure as t, DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS as tn, unproject as tr, DEFAULT_FIX_MISSION_TASK_OPTIONS as tt, DEFAULT_TURNING_MOVEMENT_OPTIONS as u, DEFAULT_SUPPRESS_OPTIONS as un, DEFAULT_DISENGAGE_OPTIONS as ut, DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS as v, DEFAULT_STROKE_WIDTH_CSS_PIXELS as vn, DEFAULT_CORDON_AND_SEARCH_OPTIONS as vt, DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS as w, supportByFireDrawRule as wn, RADAR_SEARCH_DOCTRINE_STROKE_COLOR as wt, DEFAULT_MINEFIELD_OPTIONS as x, axis1DrawRule as xn, DEFAULT_CLEAR_OPTIONS as xt, DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS as y, DEFAULT_SYMBOL_COLOR as yn, DEFAULT_CORDON_AND_KNOCK_OPTIONS as yt, DEFAULT_FORTIFIED_AREA_OPTIONS as z, penetrateDrawRule as zn, DEFAULT_BOUNDARY_OPTIONS as zt };