@orbat-mapper/control-measures 0.2.0-alpha.18 → 0.2.0-alpha.19

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.
@@ -587,7 +587,7 @@ declare const DEFAULT_LIGHT_LINE_OPTIONS: LightLineOptions;
587
587
  * Creates a Light line control measure: a polyline through `positions`
588
588
  * labeled "LL" above the line near each end.
589
589
  */
590
- declare function createLightLine(positions: Position[], options?: LightLineOptions): FeatureCollection<LineString | Point>;
590
+ declare function createLightLine(positions: Position[], options?: LightLineOptions, textAmplifiers?: CanonicalTextAmplifiers): FeatureCollection<LineString | Point>;
591
591
  //#endregion
592
592
  //#region src/generators/cm11-command-control-lines/engineer-work-line.d.ts
593
593
  /** Configuration options for the Engineer work line control measure. */
@@ -1508,7 +1508,7 @@ declare function createAttackByFire(coordinates: Position[], options?: AttackByF
1508
1508
  /**
1509
1509
  * Configuration options for the FLOT (Forward Line of Own Troops) geometry.
1510
1510
  */
1511
- interface FLOTOptions extends SmoothLineOptions {
1511
+ interface FLOTOptions extends SmoothLineOptions, LineLabelOptions {
1512
1512
  /**
1513
1513
  * The radius of the semicircular arcs in meters.
1514
1514
  * Semicircles are placed tangent to each other (diameter = 2 * radius).
@@ -1540,7 +1540,7 @@ interface FLOTOptions extends SmoothLineOptions {
1540
1540
  /**
1541
1541
  * Default options for the FLOT graphic.
1542
1542
  */
1543
- declare const DEFAULT_FLOT_OPTIONS: Required<Omit<FLOTOptions, "metersPerPixel">>;
1543
+ declare const DEFAULT_FLOT_OPTIONS: Required<Omit<FLOTOptions, keyof LineLabelOptions>>;
1544
1544
  /**
1545
1545
  * Creates a FLOT (Forward Line of Own Troops) tactical graphic.
1546
1546
  *
@@ -1560,7 +1560,7 @@ declare const DEFAULT_FLOT_OPTIONS: Required<Omit<FLOTOptions, "metersPerPixel">
1560
1560
  * );
1561
1561
  * ```
1562
1562
  */
1563
- declare function createFLOT(positions: Position[], options?: FLOTOptions): FeatureCollection<LineString>;
1563
+ declare function createFLOT(positions: Position[], options?: FLOTOptions, textAmplifiers?: CanonicalTextAmplifiers): FeatureCollection<LineString | Point>;
1564
1564
  //#endregion
1565
1565
  //#region src/generators/cm14-maneuver-lines/phase-line.d.ts
1566
1566
  /** Configuration options for the Phase line control measure. */
@@ -1606,7 +1606,7 @@ declare const DEFAULT_HANDOVER_LINE_OPTIONS: HandoverLineOptions;
1606
1606
  * Creates a Handover line control measure: a polyline through `positions`
1607
1607
  * labeled "HOL" above the line near each end.
1608
1608
  */
1609
- declare function createHandoverLine(positions: Position[], options?: HandoverLineOptions): FeatureCollection<LineString | Point>;
1609
+ declare function createHandoverLine(positions: Position[], options?: HandoverLineOptions, textAmplifiers?: CanonicalTextAmplifiers): FeatureCollection<LineString | Point>;
1610
1610
  //#endregion
1611
1611
  //#region src/generators/cm14-maneuver-lines/battle-handover-line.d.ts
1612
1612
  /** Configuration options for the Battle handover line control measure. */
@@ -1633,7 +1633,7 @@ declare const DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS: BattleHandoverLineOptions;
1633
1633
  * Creates a Battle handover line control measure: a polyline through
1634
1634
  * `positions` labeled "BHL" above the line near each end.
1635
1635
  */
1636
- declare function createBattleHandoverLine(positions: Position[], options?: BattleHandoverLineOptions): FeatureCollection<LineString | Point>;
1636
+ declare function createBattleHandoverLine(positions: Position[], options?: BattleHandoverLineOptions, textAmplifiers?: CanonicalTextAmplifiers): FeatureCollection<LineString | Point>;
1637
1637
  //#endregion
1638
1638
  //#region src/generators/cm34-mission-tasks/block.d.ts
1639
1639
  interface BlockMissionTaskOptions {
@@ -1902,7 +1902,7 @@ declare const DEFAULT_SCREEN_OPTIONS: Required<Omit<SecurityTaskOptions, "labelS
1902
1902
  declare function createScreenSymbol(coordinates: Position[], options?: ScreenOptions): FeatureCollection<MultiLineString | Point>;
1903
1903
  //#endregion
1904
1904
  //#region src/generators/cm29-protection-lines/antitankDitch.d.ts
1905
- interface AntitankDitchOptions extends SmoothLineOptions {
1905
+ interface AntitankDitchOptions extends SmoothLineOptions, LineLabelOptions {
1906
1906
  /**
1907
1907
  * The tooth depth in meters. Target tooth spacing is roughly 1.15x this depth.
1908
1908
  * Ignored when toothHeightPixels is provided with metersPerPixel.
@@ -1927,14 +1927,9 @@ interface AntitankDitchOptions extends SmoothLineOptions {
1927
1927
  */
1928
1928
  metersPerPixel?: number;
1929
1929
  }
1930
- declare const DEFAULT_ANTITANK_DITCH_OPTIONS: Required<Omit<AntitankDitchOptions, "metersPerPixel">>;
1931
- declare function createAntitankDitchUnderConstruction(positions: Position[], options?: AntitankDitchOptions): FeatureCollection<MultiLineString, {
1932
- part: "ditch";
1933
- }>;
1934
- declare function createAntitankDitchCompleted(positions: Position[], options?: AntitankDitchOptions): FeatureCollection<MultiPolygon, {
1935
- part: "teeth";
1936
- fill: boolean;
1937
- }>;
1930
+ declare const DEFAULT_ANTITANK_DITCH_OPTIONS: Required<Omit<AntitankDitchOptions, keyof LineLabelOptions>>;
1931
+ declare function createAntitankDitchUnderConstruction(positions: Position[], options?: AntitankDitchOptions, textAmplifiers?: CanonicalTextAmplifiers): FeatureCollection<MultiLineString | Point>;
1932
+ declare function createAntitankDitchCompleted(positions: Position[], options?: AntitankDitchOptions, textAmplifiers?: CanonicalTextAmplifiers): FeatureCollection<MultiPolygon | Point>;
1938
1933
  //#endregion
1939
1934
  //#region src/generators/cm29-protection-lines/antitankWall.d.ts
1940
1935
  interface AntitankWallOptions extends AntitankDitchOptions {
@@ -1945,16 +1940,14 @@ interface AntitankWallOptions extends AntitankDitchOptions {
1945
1940
  */
1946
1941
  toothSpacingRatio?: number;
1947
1942
  }
1948
- declare const DEFAULT_ANTITANK_WALL_OPTIONS: Required<Omit<AntitankWallOptions, "metersPerPixel">>;
1949
- declare function createAntitankWall(positions: Position[], options?: AntitankWallOptions): FeatureCollection<MultiLineString, {
1950
- part: "wall";
1951
- }>;
1943
+ declare const DEFAULT_ANTITANK_WALL_OPTIONS: Required<Omit<AntitankWallOptions, keyof LineLabelOptions>>;
1944
+ declare function createAntitankWall(positions: Position[], options?: AntitankWallOptions, textAmplifiers?: CanonicalTextAmplifiers): FeatureCollection<MultiLineString | Point>;
1952
1945
  //#endregion
1953
1946
  //#region src/generators/cm29-protection-lines/fortifiedLine.d.ts
1954
1947
  /**
1955
1948
  * Configuration options for the Fortified Line geometry.
1956
1949
  */
1957
- interface FortifiedLineOptions {
1950
+ interface FortifiedLineOptions extends LineLabelOptions {
1958
1951
  /**
1959
1952
  * The size of the square teeth in meters.
1960
1953
  * This controls both the width and height of the castellated pattern.
@@ -1994,7 +1987,7 @@ interface FortifiedLineOptions {
1994
1987
  /**
1995
1988
  * Default options for the Fortified Line graphic.
1996
1989
  */
1997
- declare const DEFAULT_FORTIFIED_LINE_OPTIONS: Required<Omit<FortifiedLineOptions, "metersPerPixel">>;
1990
+ declare const DEFAULT_FORTIFIED_LINE_OPTIONS: Required<Omit<FortifiedLineOptions, keyof LineLabelOptions>>;
1998
1991
  /**
1999
1992
  * Creates a Fortified Line tactical graphic.
2000
1993
  *
@@ -2005,7 +1998,7 @@ declare const DEFAULT_FORTIFIED_LINE_OPTIONS: Required<Omit<FortifiedLineOptions
2005
1998
  * @param options - Configuration options for the graphic
2006
1999
  * @returns A GeoJSON FeatureCollection containing the castellated LineString
2007
2000
  */
2008
- declare function createFortifiedLine(positions: Position[], options?: FortifiedLineOptions): FeatureCollection<LineString>;
2001
+ declare function createFortifiedLine(positions: Position[], options?: FortifiedLineOptions, textAmplifiers?: CanonicalTextAmplifiers): FeatureCollection<LineString | Point>;
2009
2002
  //#endregion
2010
2003
  //#region src/generators/cm15-maneuver-areas/fortifiedArea.d.ts
2011
2004
  /**
package/dist/index.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { $ as getDefaultOptions, $n as DEFAULT_STRONG_POINT_OPTIONS, $t as DEFAULT_FLOT_OPTIONS, A as roundToFixed, An as DEFAULT_AREA_OF_OPERATIONS_OPTIONS, Ar as normalizeTextAmplifiers, At as GuardOptions, B as StyleHints, Bn as DEFAULT_AREA_DEFENSE_OPTIONS, Bt as DEFAULT_CANALIZE_OPTIONS, C as BaselineFrame, Cn as DEFAULT_SUPPORTING_ATTACK_OPTIONS, Cr as GeneratedLabelKey, Ct as AntitankWallOptions, D as createBaselineFrame, Dn as calculateMetrics, Dr as TextAmplifierKey, Dt as DEFAULT_SCREEN_OPTIONS, E as BaselineFrameOrigin, En as MainAttackOptions, Er as TextAmplifierField, Et as DEFAULT_ANTITANK_DITCH_OPTIONS, F as freezeOrientationOptions, Fn as DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, Ft as DEFAULT_TACTICAL_ARROW_OPTIONS, G as ControlMeasureStyle, Gn as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, Gt as BlockMissionTaskOptions, H as ControlMeasure, Hn as EncirclementOptions, Ht as DEFAULT_BYPASS_OPTIONS, I as RenderOptions, In as JointTacticalActionAreaOptions, It as TacticalArrowOptions, J as ControlMeasureId, Jn as DirectionOfSupportingAttackOptions, Jt as DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, K as CONTROL_MEASURE_IDS, Kn as PrincipalDirectionOfFireOptions, Kt as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, L as renderControlMeasure, Ln as AssemblyAreaOptions, Lt as ClearOptions, M as SimpleStyleRender, Mn as PickupZoneOptions, Mr as AnchorTransformEvent, Mt as DelayOptions, N as toSimpleStyle, Nn as DEFAULT_LANDING_ZONE_OPTIONS, Nr as ControlMeasureDrawRule, Nt as CoverOptions, O as EPSILON, On as computeInitialWidthPoint, Or as TextAmplifiers, Ot as ScreenOptions, P as resolveStyleHints, Pn as LandingZoneOptions, Pt as DEFAULT_COVER_OPTIONS, Q as getControlMeasureMetadataByValue, Qn as DirectionOfAttackAviationOptions, Qt as PhaseLineOptions, R as ControlMeasureRender, Rn as DEFAULT_ASSEMBLY_AREA_OPTIONS, Rt as DEFAULT_CLEAR_OPTIONS, S as snapToMidpointPerpendicular, Sn as DEFAULT_CLASSIC_ARROW_OPTIONS, Sr as CanonicalTextAmplifiers, St as FortifiedLineOptions, T as BaselineFrameOptions, Tn as DEFAULT_MAIN_ATTACK_OPTIONS, Tr as TEXT_AMPLIFIER_FIELDS, Tt as AntitankDitchOptions, U as cloneControlMeasure, Un as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, Ut as BreachOptions, V as controlMeasureIdFromFeature, Vn as DEFAULT_ENCIRCLEMENT_OPTIONS, Vt as BypassOptions, W as isKind, Wn as FinalProtectiveFireOptions, Wt as DEFAULT_BREACH_OPTIONS, X as OptionsByKind, Xn as DirectionOfMainAttackOptions, Xt as HandoverLineOptions, Y as ControlMeasureKind, Yn as DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS, Yt as DEFAULT_HANDOVER_LINE_OPTIONS, Z as getControlMeasureMetadata, Zn as DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS, Zt as DEFAULT_PHASE_LINE_OPTIONS, _ as MidpointPerpendicularDrawRuleOptions, _n as BlockArrowHeadStyle, _r as ControlMeasureMetadata, _t as DEFAULT_FRONTAL_ATTACK_OPTIONS, a as supportByFireDrawRule, an as AttackHelicopterOptions, ar as DEFAULT_ENGINEER_WORK_LINE_OPTIONS, at as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, b as getMidpointPerpendicularSignedDistance, bn as ClassicArrowHeadStyle, br as AmplifierPlacement, bt as FortifiedAreaOptions, c as line23DrawRule, cn as DEFAULT_AIRBORNE_ATTACK_OPTIONS, cr as LightLineOptions, ct as TurnOptions, d as ambushDrawRule, dn as DEFAULT_GENERIC_RECTANGLE_OPTIONS, dr as project, dt as DEFAULT_DISRUPT_OPTIONS, en as FLOTOptions, er as StrongPointOptions, et as listControlMeasureMetadata, f as attackByFireDrawRule, fn as GenericRectangleOptions, fr as unproject, ft as DisruptOptions, g as blockDrawRule, gn as GenericLineOptions, gr as ControlMeasureGeometryType, gt as TurningMovementOptions, h as disruptDrawRule, hn as DEFAULT_GENERIC_LINE_OPTIONS, hr as ControlMeasureGeometry, ht as DEFAULT_TURNING_MOVEMENT_OPTIONS, i as axis1DrawRule, in as SupportByFireOptions, ir as GenericC2LineOptions, it as ObstacleBypassDifficultOptions, j as SimpleStyleProps, jn as DEFAULT_PICKUP_ZONE_OPTIONS, jr as resolveAmplifierPlacement, jt as DEFAULT_DELAY_OPTIONS, k as getMetersPerPixel, kn as AreaOfOperationsOptions, kr as canonicalTextAmplifierKey, kt as DEFAULT_GUARD_OPTIONS, l as turnDrawRule, ln as DEFAULT_GENERIC_CIRCLE_OPTIONS, lr as LabelSizeOptions, lt as DEFAULT_FIX_OPTIONS, m as centerRadiusDrawRule, mn as GenericPolygonOptions, mr as DEFAULT_BOUNDARY_OPTIONS, mt as DEFAULT_BLOCK_OPTIONS, n as DEFAULT_AMBUSH_OPTIONS, nn as DEFAULT_ATTACK_BY_FIRE_OPTIONS, nr as DEFAULT_BATTLE_POSITION_OPTIONS, nt as ObstacleBypassImpossibleOptions, o as line26DrawRule, on as DEFAULT_ATTACK_HELICOPTER_OPTIONS, or as EngineerWorkLineOptions, ot as ObstacleBypassEasyOptions, p as point12DrawRule, pn as DEFAULT_GENERIC_POLYGON_OPTIONS, pr as BoundaryOptions, pt as BlockOptions, q as CONTROL_MEASURE_METADATA, qn as DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS, qt as BattleHandoverLineOptions, r as rectangleDrawRule, rn as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, rr as DEFAULT_GENERIC_C2_LINE_OPTIONS, rt as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, s as line24DrawRule, sn as AirborneAttackOptions, sr as DEFAULT_LIGHT_LINE_OPTIONS, st as DEFAULT_TURN_OPTIONS, t as AmbushOptions, tn as AttackByFireOptions, tr as BattlePositionOptions, tt as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, u as line1DrawRule, un as GenericCircleOptions, ur as Point2D, ut as FixOptions, v as computeDefaultMidpointPerpendicularPoint, vn as BlockArrowOptions, vr as ParamDescriptor, vt as FrontalAttackOptions, w as BaselineFrameNormal, wn as SupportingAttackOptions, wr as LabelPlacementOverride, wt as DEFAULT_ANTITANK_WALL_OPTIONS, x as pointOnMidpointPerpendicularAxis, xn as ClassicArrowOptions, xr as AmplifierPlacements, xt as DEFAULT_FORTIFIED_LINE_OPTIONS, y as createMidpointPerpendicularDrawRule, yn as DEFAULT_BLOCK_ARROW_OPTIONS, yr as TextAmplifierDescriptor, yt as DEFAULT_FORTIFIED_AREA_OPTIONS, z as FeaturePartProps, zn as AreaDefenseOptions, zt as CanalizeOptions } from "./index-CFTEcmQi.mjs";
1
+ import { $ as getDefaultOptions, $n as DEFAULT_STRONG_POINT_OPTIONS, $t as DEFAULT_FLOT_OPTIONS, A as roundToFixed, An as DEFAULT_AREA_OF_OPERATIONS_OPTIONS, Ar as normalizeTextAmplifiers, At as GuardOptions, B as StyleHints, Bn as DEFAULT_AREA_DEFENSE_OPTIONS, Bt as DEFAULT_CANALIZE_OPTIONS, C as BaselineFrame, Cn as DEFAULT_SUPPORTING_ATTACK_OPTIONS, Cr as GeneratedLabelKey, Ct as AntitankWallOptions, D as createBaselineFrame, Dn as calculateMetrics, Dr as TextAmplifierKey, Dt as DEFAULT_SCREEN_OPTIONS, E as BaselineFrameOrigin, En as MainAttackOptions, Er as TextAmplifierField, Et as DEFAULT_ANTITANK_DITCH_OPTIONS, F as freezeOrientationOptions, Fn as DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, Ft as DEFAULT_TACTICAL_ARROW_OPTIONS, G as ControlMeasureStyle, Gn as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, Gt as BlockMissionTaskOptions, H as ControlMeasure, Hn as EncirclementOptions, Ht as DEFAULT_BYPASS_OPTIONS, I as RenderOptions, In as JointTacticalActionAreaOptions, It as TacticalArrowOptions, J as ControlMeasureId, Jn as DirectionOfSupportingAttackOptions, Jt as DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, K as CONTROL_MEASURE_IDS, Kn as PrincipalDirectionOfFireOptions, Kt as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, L as renderControlMeasure, Ln as AssemblyAreaOptions, Lt as ClearOptions, M as SimpleStyleRender, Mn as PickupZoneOptions, Mr as AnchorTransformEvent, Mt as DelayOptions, N as toSimpleStyle, Nn as DEFAULT_LANDING_ZONE_OPTIONS, Nr as ControlMeasureDrawRule, Nt as CoverOptions, O as EPSILON, On as computeInitialWidthPoint, Or as TextAmplifiers, Ot as ScreenOptions, P as resolveStyleHints, Pn as LandingZoneOptions, Pt as DEFAULT_COVER_OPTIONS, Q as getControlMeasureMetadataByValue, Qn as DirectionOfAttackAviationOptions, Qt as PhaseLineOptions, R as ControlMeasureRender, Rn as DEFAULT_ASSEMBLY_AREA_OPTIONS, Rt as DEFAULT_CLEAR_OPTIONS, S as snapToMidpointPerpendicular, Sn as DEFAULT_CLASSIC_ARROW_OPTIONS, Sr as CanonicalTextAmplifiers, St as FortifiedLineOptions, T as BaselineFrameOptions, Tn as DEFAULT_MAIN_ATTACK_OPTIONS, Tr as TEXT_AMPLIFIER_FIELDS, Tt as AntitankDitchOptions, U as cloneControlMeasure, Un as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, Ut as BreachOptions, V as controlMeasureIdFromFeature, Vn as DEFAULT_ENCIRCLEMENT_OPTIONS, Vt as BypassOptions, W as isKind, Wn as FinalProtectiveFireOptions, Wt as DEFAULT_BREACH_OPTIONS, X as OptionsByKind, Xn as DirectionOfMainAttackOptions, Xt as HandoverLineOptions, Y as ControlMeasureKind, Yn as DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS, Yt as DEFAULT_HANDOVER_LINE_OPTIONS, Z as getControlMeasureMetadata, Zn as DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS, Zt as DEFAULT_PHASE_LINE_OPTIONS, _ as MidpointPerpendicularDrawRuleOptions, _n as BlockArrowHeadStyle, _r as ControlMeasureMetadata, _t as DEFAULT_FRONTAL_ATTACK_OPTIONS, a as supportByFireDrawRule, an as AttackHelicopterOptions, ar as DEFAULT_ENGINEER_WORK_LINE_OPTIONS, at as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, b as getMidpointPerpendicularSignedDistance, bn as ClassicArrowHeadStyle, br as AmplifierPlacement, bt as FortifiedAreaOptions, c as line23DrawRule, cn as DEFAULT_AIRBORNE_ATTACK_OPTIONS, cr as LightLineOptions, ct as TurnOptions, d as ambushDrawRule, dn as DEFAULT_GENERIC_RECTANGLE_OPTIONS, dr as project, dt as DEFAULT_DISRUPT_OPTIONS, en as FLOTOptions, er as StrongPointOptions, et as listControlMeasureMetadata, f as attackByFireDrawRule, fn as GenericRectangleOptions, fr as unproject, ft as DisruptOptions, g as blockDrawRule, gn as GenericLineOptions, gr as ControlMeasureGeometryType, gt as TurningMovementOptions, h as disruptDrawRule, hn as DEFAULT_GENERIC_LINE_OPTIONS, hr as ControlMeasureGeometry, ht as DEFAULT_TURNING_MOVEMENT_OPTIONS, i as axis1DrawRule, in as SupportByFireOptions, ir as GenericC2LineOptions, it as ObstacleBypassDifficultOptions, j as SimpleStyleProps, jn as DEFAULT_PICKUP_ZONE_OPTIONS, jr as resolveAmplifierPlacement, jt as DEFAULT_DELAY_OPTIONS, k as getMetersPerPixel, kn as AreaOfOperationsOptions, kr as canonicalTextAmplifierKey, kt as DEFAULT_GUARD_OPTIONS, l as turnDrawRule, ln as DEFAULT_GENERIC_CIRCLE_OPTIONS, lr as LabelSizeOptions, lt as DEFAULT_FIX_OPTIONS, m as centerRadiusDrawRule, mn as GenericPolygonOptions, mr as DEFAULT_BOUNDARY_OPTIONS, mt as DEFAULT_BLOCK_OPTIONS, n as DEFAULT_AMBUSH_OPTIONS, nn as DEFAULT_ATTACK_BY_FIRE_OPTIONS, nr as DEFAULT_BATTLE_POSITION_OPTIONS, nt as ObstacleBypassImpossibleOptions, o as line26DrawRule, on as DEFAULT_ATTACK_HELICOPTER_OPTIONS, or as EngineerWorkLineOptions, ot as ObstacleBypassEasyOptions, p as point12DrawRule, pn as DEFAULT_GENERIC_POLYGON_OPTIONS, pr as BoundaryOptions, pt as BlockOptions, q as CONTROL_MEASURE_METADATA, qn as DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS, qt as BattleHandoverLineOptions, r as rectangleDrawRule, rn as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, rr as DEFAULT_GENERIC_C2_LINE_OPTIONS, rt as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, s as line24DrawRule, sn as AirborneAttackOptions, sr as DEFAULT_LIGHT_LINE_OPTIONS, st as DEFAULT_TURN_OPTIONS, t as AmbushOptions, tn as AttackByFireOptions, tr as BattlePositionOptions, tt as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, u as line1DrawRule, un as GenericCircleOptions, ur as Point2D, ut as FixOptions, v as computeDefaultMidpointPerpendicularPoint, vn as BlockArrowOptions, vr as ParamDescriptor, vt as FrontalAttackOptions, w as BaselineFrameNormal, wn as SupportingAttackOptions, wr as LabelPlacementOverride, wt as DEFAULT_ANTITANK_WALL_OPTIONS, x as pointOnMidpointPerpendicularAxis, xn as ClassicArrowOptions, xr as AmplifierPlacements, xt as DEFAULT_FORTIFIED_LINE_OPTIONS, y as createMidpointPerpendicularDrawRule, yn as DEFAULT_BLOCK_ARROW_OPTIONS, yr as TextAmplifierDescriptor, yt as DEFAULT_FORTIFIED_AREA_OPTIONS, z as FeaturePartProps, zn as AreaDefenseOptions, zt as CanalizeOptions } from "./index-BJwZXCKb.mjs";
2
2
  export { type AirborneAttackOptions, type AmbushOptions, type AmplifierPlacement, type AmplifierPlacements, type AnchorTransformEvent, type AntitankDitchOptions, type AntitankWallOptions, type AreaDefenseOptions, type AreaOfOperationsOptions, type AssemblyAreaOptions, type AttackByFireOptions, type AttackHelicopterOptions, type BaselineFrame, type BaselineFrameNormal, type BaselineFrameOptions, type BaselineFrameOrigin, type BattleHandoverLineOptions, type BattlePositionOptions, type BlockArrowHeadStyle, type BlockArrowOptions, type BlockMissionTaskOptions, type BlockOptions, type BoundaryOptions, type BreachOptions, type BypassOptions, CONTROL_MEASURE_IDS, CONTROL_MEASURE_METADATA, type CanalizeOptions, type CanonicalTextAmplifiers, type ClassicArrowHeadStyle, type ClassicArrowOptions, type ClearOptions, type ControlMeasure, type ControlMeasureDrawRule, type ControlMeasureGeometry, type ControlMeasureGeometryType, type ControlMeasureId, type ControlMeasureKind, type ControlMeasureMetadata, type ControlMeasureRender, type ControlMeasureStyle, type CoverOptions, DEFAULT_AIRBORNE_ATTACK_OPTIONS, DEFAULT_AMBUSH_OPTIONS, DEFAULT_ANTITANK_DITCH_OPTIONS, DEFAULT_ANTITANK_WALL_OPTIONS, DEFAULT_AREA_DEFENSE_OPTIONS, DEFAULT_AREA_OF_OPERATIONS_OPTIONS, DEFAULT_ASSEMBLY_AREA_OPTIONS, DEFAULT_ATTACK_BY_FIRE_OPTIONS, DEFAULT_ATTACK_HELICOPTER_OPTIONS, DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, DEFAULT_BATTLE_POSITION_OPTIONS, DEFAULT_BLOCK_ARROW_OPTIONS, DEFAULT_BLOCK_MISSION_TASK_OPTIONS, DEFAULT_BLOCK_OPTIONS, DEFAULT_BOUNDARY_OPTIONS, DEFAULT_BREACH_OPTIONS, DEFAULT_BYPASS_OPTIONS, DEFAULT_CANALIZE_OPTIONS, DEFAULT_CLASSIC_ARROW_OPTIONS, DEFAULT_CLEAR_OPTIONS, DEFAULT_COVER_OPTIONS, DEFAULT_DELAY_OPTIONS, DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS, DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS, DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS, DEFAULT_DISRUPT_OPTIONS, DEFAULT_ENCIRCLEMENT_OPTIONS, DEFAULT_ENGINEER_WORK_LINE_OPTIONS, DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, DEFAULT_FIX_OPTIONS, DEFAULT_FLOT_OPTIONS, DEFAULT_FORTIFIED_AREA_OPTIONS, DEFAULT_FORTIFIED_LINE_OPTIONS, DEFAULT_FRONTAL_ATTACK_OPTIONS, DEFAULT_GENERIC_C2_LINE_OPTIONS, DEFAULT_GENERIC_CIRCLE_OPTIONS, DEFAULT_GENERIC_LINE_OPTIONS, DEFAULT_GENERIC_POLYGON_OPTIONS, DEFAULT_GENERIC_RECTANGLE_OPTIONS, DEFAULT_GUARD_OPTIONS, DEFAULT_HANDOVER_LINE_OPTIONS, DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, DEFAULT_LANDING_ZONE_OPTIONS, DEFAULT_LIGHT_LINE_OPTIONS, DEFAULT_MAIN_ATTACK_OPTIONS, DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, DEFAULT_PHASE_LINE_OPTIONS, DEFAULT_PICKUP_ZONE_OPTIONS, DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, DEFAULT_SCREEN_OPTIONS, DEFAULT_STRONG_POINT_OPTIONS, DEFAULT_SUPPORTING_ATTACK_OPTIONS, DEFAULT_SUPPORT_BY_FIRE_OPTIONS, DEFAULT_TACTICAL_ARROW_OPTIONS, DEFAULT_TURNING_MOVEMENT_OPTIONS, DEFAULT_TURN_OPTIONS, type DelayOptions, type DirectionOfAttackAviationOptions, type DirectionOfMainAttackOptions, type DirectionOfSupportingAttackOptions, type DisruptOptions, EPSILON, type EncirclementOptions, type EngineerWorkLineOptions, type FLOTOptions, type FeaturePartProps, type FinalProtectiveFireOptions, type FixOptions, type FortifiedAreaOptions, type FortifiedLineOptions, type FrontalAttackOptions, type GeneratedLabelKey, type GenericC2LineOptions, type GenericCircleOptions, type GenericLineOptions, type GenericPolygonOptions, type GenericRectangleOptions, type GuardOptions, type HandoverLineOptions, type JointTacticalActionAreaOptions, type LabelPlacementOverride, type LabelSizeOptions, type LandingZoneOptions, type LightLineOptions, type MainAttackOptions, type MidpointPerpendicularDrawRuleOptions, type ObstacleBypassDifficultOptions, type ObstacleBypassEasyOptions, type ObstacleBypassImpossibleOptions, type OptionsByKind, type ParamDescriptor, type PhaseLineOptions, type PickupZoneOptions, type Point2D, type PrincipalDirectionOfFireOptions, type RenderOptions, type ScreenOptions, type SimpleStyleProps, type SimpleStyleRender, type StrongPointOptions, type StyleHints, type SupportByFireOptions, type SupportingAttackOptions, TEXT_AMPLIFIER_FIELDS, type TacticalArrowOptions, type TextAmplifierDescriptor, type TextAmplifierField, type TextAmplifierKey, type TextAmplifiers, type TurnOptions, type TurningMovementOptions, ambushDrawRule, attackByFireDrawRule, axis1DrawRule, blockDrawRule, calculateMetrics, canonicalTextAmplifierKey, centerRadiusDrawRule, cloneControlMeasure, computeDefaultMidpointPerpendicularPoint, computeInitialWidthPoint, controlMeasureIdFromFeature, createBaselineFrame, createMidpointPerpendicularDrawRule, disruptDrawRule, freezeOrientationOptions, getControlMeasureMetadata, getControlMeasureMetadataByValue, getDefaultOptions, getMetersPerPixel, getMidpointPerpendicularSignedDistance, isKind, line1DrawRule, line23DrawRule, line24DrawRule, line26DrawRule, listControlMeasureMetadata, normalizeTextAmplifiers, point12DrawRule, pointOnMidpointPerpendicularAxis, project, rectangleDrawRule, renderControlMeasure, resolveAmplifierPlacement, resolveStyleHints, roundToFixed, snapToMidpointPerpendicular, supportByFireDrawRule, toSimpleStyle, turnDrawRule, unproject };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as DEFAULT_BLOCK_ARROW_OPTIONS, A as DEFAULT_FLOT_OPTIONS, At as disruptDrawRule, B as DEFAULT_GENERIC_RECTANGLE_OPTIONS, Bt as project, C as DEFAULT_SCREEN_OPTIONS, Ct as line23DrawRule, D as DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, Dt as attackByFireDrawRule, E as DEFAULT_FORTIFIED_LINE_OPTIONS, Et as ambushDrawRule, F as DEFAULT_GUARD_OPTIONS, Ft as pointOnMidpointPerpendicularAxis, G as DEFAULT_CANALIZE_OPTIONS, H as DEFAULT_GENERIC_LINE_OPTIONS, Ht as EPSILON, I as DEFAULT_DELAY_OPTIONS, It as snapToMidpointPerpendicular, J as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, K as DEFAULT_BYPASS_OPTIONS, L as DEFAULT_COVER_OPTIONS, Lt as createBaselineFrame, M as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, Mt as computeDefaultMidpointPerpendicularPoint, N as DEFAULT_ENCIRCLEMENT_OPTIONS, Nt as createMidpointPerpendicularDrawRule, O as DEFAULT_HANDOVER_LINE_OPTIONS, Ot as point12DrawRule, P as DEFAULT_DISRUPT_OPTIONS, Pt as getMidpointPerpendicularSignedDistance, Q as DEFAULT_BOUNDARY_OPTIONS, R as DEFAULT_TACTICAL_ARROW_OPTIONS, Rt as calculateMetrics, S as DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, St as line24DrawRule, T as DEFAULT_FORTIFIED_AREA_OPTIONS, Tt as line1DrawRule, U as DEFAULT_GENERIC_CIRCLE_OPTIONS, Ut as getMetersPerPixel, V as DEFAULT_GENERIC_POLYGON_OPTIONS, Vt as unproject, W as DEFAULT_CLASSIC_ARROW_OPTIONS, Wt as roundToFixed, X as DEFAULT_ENGINEER_WORK_LINE_OPTIONS, Y as DEFAULT_GENERIC_C2_LINE_OPTIONS, Z as DEFAULT_LIGHT_LINE_OPTIONS, _ as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, _t as DEFAULT_AIRBORNE_ATTACK_OPTIONS, a as DEFINITIONS, at as DEFAULT_ANTITANK_DITCH_OPTIONS, b as DEFAULT_MAIN_ATTACK_OPTIONS, bt as supportByFireDrawRule, c as getDefaultOptions, ct as DEFAULT_AREA_DEFENSE_OPTIONS, d as DEFAULT_TURN_OPTIONS, dt as normalizeTextAmplifiers, et as DEFAULT_BLOCK_OPTIONS, f as DEFAULT_SUPPORTING_ATTACK_OPTIONS, ft as resolveAmplifierPlacement, g as DEFAULT_PICKUP_ZONE_OPTIONS, gt as DEFAULT_AMBUSH_OPTIONS, h as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, ht as DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS, i as CONTROL_MEASURE_METADATA, it as DEFAULT_ANTITANK_WALL_OPTIONS, j as DEFAULT_FIX_OPTIONS, jt as blockDrawRule, k as DEFAULT_PHASE_LINE_OPTIONS, kt as centerRadiusDrawRule, l as listControlMeasureMetadata, lt as TEXT_AMPLIFIER_FIELDS, m as DEFAULT_STRONG_POINT_OPTIONS, mt as DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS, n as resolveStyleHints, nt as DEFAULT_ATTACK_HELICOPTER_OPTIONS, o as getControlMeasureMetadata, ot as DEFAULT_ASSEMBLY_AREA_OPTIONS, p as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, pt as DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS, q as DEFAULT_BREACH_OPTIONS, r as CONTROL_MEASURE_IDS, rt as DEFAULT_ATTACK_BY_FIRE_OPTIONS, s as getControlMeasureMetadataByValue, st as DEFAULT_AREA_OF_OPERATIONS_OPTIONS, t as renderControlMeasure, tt as DEFAULT_BATTLE_POSITION_OPTIONS, u as DEFAULT_TURNING_MOVEMENT_OPTIONS, ut as canonicalTextAmplifierKey, v as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, vt as rectangleDrawRule, w as DEFAULT_FRONTAL_ATTACK_OPTIONS, wt as turnDrawRule, x as DEFAULT_LANDING_ZONE_OPTIONS, xt as line26DrawRule, y as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, yt as axis1DrawRule, z as DEFAULT_CLEAR_OPTIONS, zt as computeInitialWidthPoint } from "./renderControlMeasure-C1Ur1rH0.mjs";
1
+ import { $ as DEFAULT_BLOCK_ARROW_OPTIONS, A as DEFAULT_FLOT_OPTIONS, At as disruptDrawRule, B as DEFAULT_GENERIC_RECTANGLE_OPTIONS, Bt as project, C as DEFAULT_SCREEN_OPTIONS, Ct as line23DrawRule, D as DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, Dt as attackByFireDrawRule, E as DEFAULT_FORTIFIED_LINE_OPTIONS, Et as ambushDrawRule, F as DEFAULT_GUARD_OPTIONS, Ft as pointOnMidpointPerpendicularAxis, G as DEFAULT_CANALIZE_OPTIONS, H as DEFAULT_GENERIC_LINE_OPTIONS, Ht as EPSILON, I as DEFAULT_DELAY_OPTIONS, It as snapToMidpointPerpendicular, J as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, K as DEFAULT_BYPASS_OPTIONS, L as DEFAULT_COVER_OPTIONS, Lt as createBaselineFrame, M as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, Mt as computeDefaultMidpointPerpendicularPoint, N as DEFAULT_ENCIRCLEMENT_OPTIONS, Nt as createMidpointPerpendicularDrawRule, O as DEFAULT_HANDOVER_LINE_OPTIONS, Ot as point12DrawRule, P as DEFAULT_DISRUPT_OPTIONS, Pt as getMidpointPerpendicularSignedDistance, Q as DEFAULT_BOUNDARY_OPTIONS, R as DEFAULT_TACTICAL_ARROW_OPTIONS, Rt as calculateMetrics, S as DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, St as line24DrawRule, T as DEFAULT_FORTIFIED_AREA_OPTIONS, Tt as line1DrawRule, U as DEFAULT_GENERIC_CIRCLE_OPTIONS, Ut as getMetersPerPixel, V as DEFAULT_GENERIC_POLYGON_OPTIONS, Vt as unproject, W as DEFAULT_CLASSIC_ARROW_OPTIONS, Wt as roundToFixed, X as DEFAULT_ENGINEER_WORK_LINE_OPTIONS, Y as DEFAULT_GENERIC_C2_LINE_OPTIONS, Z as DEFAULT_LIGHT_LINE_OPTIONS, _ as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, _t as DEFAULT_AIRBORNE_ATTACK_OPTIONS, a as DEFINITIONS, at as DEFAULT_ANTITANK_DITCH_OPTIONS, b as DEFAULT_MAIN_ATTACK_OPTIONS, bt as supportByFireDrawRule, c as getDefaultOptions, ct as DEFAULT_AREA_DEFENSE_OPTIONS, d as DEFAULT_TURN_OPTIONS, dt as normalizeTextAmplifiers, et as DEFAULT_BLOCK_OPTIONS, f as DEFAULT_SUPPORTING_ATTACK_OPTIONS, ft as resolveAmplifierPlacement, g as DEFAULT_PICKUP_ZONE_OPTIONS, gt as DEFAULT_AMBUSH_OPTIONS, h as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, ht as DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS, i as CONTROL_MEASURE_METADATA, it as DEFAULT_ANTITANK_WALL_OPTIONS, j as DEFAULT_FIX_OPTIONS, jt as blockDrawRule, k as DEFAULT_PHASE_LINE_OPTIONS, kt as centerRadiusDrawRule, l as listControlMeasureMetadata, lt as TEXT_AMPLIFIER_FIELDS, m as DEFAULT_STRONG_POINT_OPTIONS, mt as DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS, n as resolveStyleHints, nt as DEFAULT_ATTACK_HELICOPTER_OPTIONS, o as getControlMeasureMetadata, ot as DEFAULT_ASSEMBLY_AREA_OPTIONS, p as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, pt as DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS, q as DEFAULT_BREACH_OPTIONS, r as CONTROL_MEASURE_IDS, rt as DEFAULT_ATTACK_BY_FIRE_OPTIONS, s as getControlMeasureMetadataByValue, st as DEFAULT_AREA_OF_OPERATIONS_OPTIONS, t as renderControlMeasure, tt as DEFAULT_BATTLE_POSITION_OPTIONS, u as DEFAULT_TURNING_MOVEMENT_OPTIONS, ut as canonicalTextAmplifierKey, v as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, vt as rectangleDrawRule, w as DEFAULT_FRONTAL_ATTACK_OPTIONS, wt as turnDrawRule, x as DEFAULT_LANDING_ZONE_OPTIONS, xt as line26DrawRule, y as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, yt as axis1DrawRule, z as DEFAULT_CLEAR_OPTIONS, zt as computeInitialWidthPoint } from "./renderControlMeasure-1e_k10Kq.mjs";
2
2
  //#region src/freeze-orientation.ts
3
3
  /**
4
4
  * Dispatches to a measure kind's `freezeOrientation` hook (see
@@ -1,4 +1,4 @@
1
- import { J as ControlMeasureId, Or as TextAmplifiers } from "../index-CFTEcmQi.mjs";
1
+ import { J as ControlMeasureId, Or as TextAmplifiers } from "../index-BJwZXCKb.mjs";
2
2
  import { FeatureCollection, Geometry } from "geojson";
3
3
 
4
4
  //#region src/preview/index.d.ts
@@ -1,4 +1,4 @@
1
- import { a as DEFINITIONS, t as renderControlMeasure } from "../renderControlMeasure-C1Ur1rH0.mjs";
1
+ import { a as DEFINITIONS, t as renderControlMeasure } from "../renderControlMeasure-1e_k10Kq.mjs";
2
2
  //#region src/preview/index.ts
3
3
  /**
4
4
  * Unitless `previewSample` points (~`[-1, 1]`) are scaled by this degree offset
@@ -2125,6 +2125,24 @@ function endTangents(verts) {
2125
2125
  }
2126
2126
  };
2127
2127
  }
2128
+ /** Field N descriptor shared by Line1 graphics that opt into hostile endpoint markers. */
2129
+ const HOSTILE_LINE_AMPLIFIER = {
2130
+ key: "N",
2131
+ label: "Hostile (ENY) marker",
2132
+ description: "Field N — literal \"ENY\" marker beyond both ends of the line.",
2133
+ placeholder: "ENY",
2134
+ maxLength: 3
2135
+ };
2136
+ /** Label-padding control shared by newly label-bearing Line1 graphics. */
2137
+ const LINE_LABEL_PADDING_PARAM = {
2138
+ key: "labelPadding",
2139
+ label: "Label padding",
2140
+ description: "Extra clearance between the line and its labels, as a ratio of the label height",
2141
+ type: "number",
2142
+ min: 0,
2143
+ max: 2,
2144
+ step: .05
2145
+ };
2128
2146
  /**
2129
2147
  * Resolves {@link LabelSizeOptions} into the single text-size property the
2130
2148
  * label feature carries (ADR-0028): `textSizePixels` when screen-anchored
@@ -2210,6 +2228,41 @@ function pushEndLabels(out, verts, textForEnd, options = {}) {
2210
2228
  }
2211
2229
  }
2212
2230
  /**
2231
+ * Approximate sans-serif character width/height ratio, used to estimate a
2232
+ * label's rendered text width from its character count when no live text
2233
+ * measurement is available at generator time.
2234
+ */
2235
+ const LABEL_CHAR_ASPECT_RATIO = .6;
2236
+ /** Estimated rendered width of `text` given its resolved label height in meters. */
2237
+ function estimatedTextWidth(text, textHeightMeters) {
2238
+ return text.length * LABEL_CHAR_ASPECT_RATIO * textHeightMeters;
2239
+ }
2240
+ /** The end-label text for a phase-line naming, or `""` when unnamed. */
2241
+ function phaseLineLabelText(name, includePrefix) {
2242
+ if (!name) return "";
2243
+ return includePrefix ? `PL ${name}` : name;
2244
+ }
2245
+ /**
2246
+ * Places a Field N hostile marker beyond each end of `verts`, following the
2247
+ * same tangent, rotation, anchor, size, and padding conventions as
2248
+ * {@link pushEndLabels}. When another beyond-tip label is present, its
2249
+ * estimated width is added so the hostile marker remains outermost.
2250
+ */
2251
+ function pushHostileEndLabels(out, verts, hostileText, options = {}, occupiedTextForEnd = "") {
2252
+ if (!hostileText) return;
2253
+ const frames = endFrames(verts);
2254
+ const sizeProps = labelSizeProps(options);
2255
+ const textHeight = resolveLabelOffsetMeters(options, 1);
2256
+ const clearance = resolveLabelOffsetMeters(options, END_LABEL_CLEARANCE_RATIO + Math.max(0, options.labelPadding ?? 0));
2257
+ for (const end of ["start", "end"]) {
2258
+ const frame = frames[end];
2259
+ if (!frame) continue;
2260
+ const occupiedText = typeof occupiedTextForEnd === "string" ? occupiedTextForEnd : occupiedTextForEnd(end);
2261
+ const distance = clearance + (occupiedText ? estimatedTextWidth(occupiedText, textHeight) + clearance : 0);
2262
+ pushLabel(out, vecAdd(frame.point, vecScale(frame.along, distance)), hostileText, labelRotationAlong(frame.along), sizeProps, frame.along[0] >= 0 ? "start" : "end", "N", `label:N:${end}`);
2263
+ }
2264
+ }
2265
+ /**
2213
2266
  * Resolves the {@link AboveEndFrame} at each tip of `verts` (projected meters):
2214
2267
  * a base point inset from the tip toward the interior, the segment's own
2215
2268
  * natural `perp` (so "above" = `+perp` reads the same at both ends), the
@@ -2264,7 +2317,7 @@ function pushEndLabelsAbove(out, verts, textForEnd, options = {}) {
2264
2317
  * (via {@link pushEndLabels} or {@link pushEndLabelsAbove}, per `placement`)
2265
2318
  * as a complete FeatureCollection.
2266
2319
  */
2267
- function fixedLabelLineFeatures(positions, options, textForEnd) {
2320
+ function fixedLabelLineFeatures(positions, options, textForEnd, hostileText) {
2268
2321
  const { part, placement = "beyond", phaseLineName, includePrefix = true, smooth, smoothResolution, ...sizeOptions } = options;
2269
2322
  const verts = smoothLineVerts(positions.map((p) => project(p[0], p[1])), {
2270
2323
  smooth,
@@ -2282,8 +2335,9 @@ function fixedLabelLineFeatures(positions, options, textForEnd) {
2282
2335
  const labelFeatures = [];
2283
2336
  if (placement === "above") pushEndLabelsAbove(labelFeatures, verts, textForEnd, sizeOptions);
2284
2337
  else pushEndLabels(labelFeatures, verts, textForEnd, sizeOptions);
2285
- const trimmedPhaseLineName = phaseLineName?.trim();
2286
- if (trimmedPhaseLineName) pushEndLabels(labelFeatures, verts, includePrefix ? `PL ${trimmedPhaseLineName}` : trimmedPhaseLineName, sizeOptions);
2338
+ const nameText = phaseLineLabelText(phaseLineName?.trim(), includePrefix);
2339
+ if (nameText) pushEndLabels(labelFeatures, verts, nameText, sizeOptions);
2340
+ pushHostileEndLabels(labelFeatures, verts, hostileText, sizeOptions, nameText || (placement === "beyond" ? textForEnd : ""));
2287
2341
  features.push(...labelFeatures);
2288
2342
  return {
2289
2343
  type: "FeatureCollection",
@@ -2295,8 +2349,6 @@ function fixedLabelLineFeatures(positions, options, textForEnd) {
2295
2349
  const DEFAULT_DIRECTION_ARROWHEAD_LENGTH_RATIO = .12;
2296
2350
  const DEFAULT_DIRECTION_ARROWHEAD_WIDTH_RATIO = 1.15;
2297
2351
  const DEFAULT_DIRECTION_LABEL_POSITION = .5;
2298
- /** Approximate sans-serif character width/height ratio used for the T knockout. */
2299
- const LABEL_CHAR_ASPECT_RATIO = .6;
2300
2352
  /** Clear space on each side of T, as a ratio of the resolved label height. */
2301
2353
  const LABEL_GAP_CLEARANCE_RATIO = .3;
2302
2354
  function nonNegative$1(value, fallback) {
@@ -2306,7 +2358,7 @@ function nonNegative$1(value, fallback) {
2306
2358
  function directionLabelGap(totalLength, fraction, text, options) {
2307
2359
  if (!text) return void 0;
2308
2360
  const textHeight = resolveLabelOffsetMeters(options, 1);
2309
- const textWidth = text.length * LABEL_CHAR_ASPECT_RATIO * textHeight;
2361
+ const textWidth = estimatedTextWidth(text, textHeight);
2310
2362
  const clearance = (LABEL_GAP_CLEARANCE_RATIO + Math.max(0, options.labelPadding ?? 0)) * textHeight;
2311
2363
  const halfGap = textWidth / 2 + clearance;
2312
2364
  const center = fraction * totalLength;
@@ -3087,11 +3139,6 @@ const ROW_PITCH_RATIO = 1.2;
3087
3139
  * ENY marker's own half-width/half-height when carving its boundary
3088
3140
  * knockout gap (see {@link pushAreaLabels}). */
3089
3141
  const ENY_CLEARANCE_RATIO = .3;
3090
- /** Approximate sans-serif character aspect ratio (width/height) used to
3091
- * estimate an ENY marker's rendered text width from its character count,
3092
- * for sizing the boundary knockout gap — no live text-measurement is
3093
- * available at generator time. */
3094
- const ENY_CHAR_ASPECT_RATIO = .6;
3095
3142
  const DEFAULT_SMOOTH_RESOLUTION$9 = 16;
3096
3143
  /**
3097
3144
  * Composes an area's main label text from a `prefix` (e.g. `"AO"`) and a
@@ -3250,7 +3297,7 @@ function labelHalfExtent(direction, textWidth, textHeight, rotation) {
3250
3297
  * its width):
3251
3298
  * `halfExtent = 0.5 * (textWidth·|d.x| + textHeight·|d.y|) + clearance`, where
3252
3299
  * `textHeight = resolveLabelOffsetMeters(options, 1)`,
3253
- * `textWidth = text.length * ENY_CHAR_ASPECT_RATIO * textHeight`, and
3300
+ * `textWidth = text.length * LABEL_CHAR_ASPECT_RATIO * textHeight`, and
3254
3301
  * `clearance = (ENY_CLEARANCE_RATIO + labelPadding) * textHeight` — mirroring
3255
3302
  * {@link placeEchelon}'s glyph-width masking gap (ADR-0023). Fewer than two
3256
3303
  * crossings (e.g. a degenerate ring, or a concave shape whose centroid
@@ -3291,7 +3338,7 @@ function pushAreaLabels(out, ringVerts, texts, options = {}, amplifierPlacements
3291
3338
  if (crossings.length >= 2) {
3292
3339
  const byX = [...crossings].sort((a, b) => a.x - b.x);
3293
3340
  const textHeight = resolveLabelOffsetMeters(options, 1);
3294
- const textWidth = texts.hostile.length * ENY_CHAR_ASPECT_RATIO * textHeight;
3341
+ const textWidth = estimatedTextWidth(texts.hostile, textHeight);
3295
3342
  const clearance = (ENY_CLEARANCE_RATIO + padding) * textHeight + Math.max(0, maskBoundary?.extraClearanceMeters ?? 0);
3296
3343
  for (const [side, crossing] of [["west", byX[0]], ["east", byX[byX.length - 1]]]) {
3297
3344
  const labelPlacementKey = `label:N:${side}`;
@@ -4192,7 +4239,8 @@ const FORTIFIED_PARAMS = [
4192
4239
  max: 500,
4193
4240
  step: 1,
4194
4241
  unit: "m"
4195
- }
4242
+ },
4243
+ LINE_LABEL_PADDING_PARAM
4196
4244
  ];
4197
4245
  const ANTITANK_DITCH_PARAMS = [
4198
4246
  ...SMOOTH_LINE_PARAMS,
@@ -4225,7 +4273,8 @@ const ANTITANK_DITCH_PARAMS = [
4225
4273
  max: 3,
4226
4274
  step: .05,
4227
4275
  unit: "x"
4228
- }
4276
+ },
4277
+ LINE_LABEL_PADDING_PARAM
4229
4278
  ];
4230
4279
  const ANTITANK_WALL_PARAMS = [...ANTITANK_DITCH_PARAMS, {
4231
4280
  key: "toothSpacingRatio",
@@ -4259,9 +4308,11 @@ const ANTITANK_DITCH_UNDER_CONSTRUCTION_METADATA = {
4259
4308
  value: "290201",
4260
4309
  minCoordinates: 2,
4261
4310
  geometry: "line",
4262
- geometryTypes: ["MultiLineString"],
4311
+ geometryTypes: ["MultiLineString", "Point"],
4263
4312
  drawRule: "Line1",
4264
- params: ANTITANK_DITCH_PARAMS
4313
+ capturesLabelSize: true,
4314
+ params: ANTITANK_DITCH_PARAMS,
4315
+ textAmplifiers: [HOSTILE_LINE_AMPLIFIER]
4265
4316
  };
4266
4317
  const ANTITANK_DITCH_COMPLETED_METADATA = {
4267
4318
  id: "antitank-ditch-completed",
@@ -4273,9 +4324,11 @@ const ANTITANK_DITCH_COMPLETED_METADATA = {
4273
4324
  value: "290202",
4274
4325
  minCoordinates: 2,
4275
4326
  geometry: "line",
4276
- geometryTypes: ["MultiPolygon"],
4327
+ geometryTypes: ["MultiPolygon", "Point"],
4277
4328
  drawRule: "Line1",
4278
- params: ANTITANK_DITCH_PARAMS
4329
+ capturesLabelSize: true,
4330
+ params: ANTITANK_DITCH_PARAMS,
4331
+ textAmplifiers: [HOSTILE_LINE_AMPLIFIER]
4279
4332
  };
4280
4333
  function calculateAntitankDitchHeight(options) {
4281
4334
  const { toothHeight = DEFAULT_TOOTH_HEIGHT, toothHeightPixels, metersPerPixel } = options;
@@ -4324,9 +4377,13 @@ function smoothedDitchBasePath(positions, options) {
4324
4377
  function buildAntitankDitchTriangles(basePath, options) {
4325
4378
  return generateAntitankDitchTriangles(basePath, calculateAntitankDitchHeight(options), options.toothWidthRatio ?? DEFAULT_TOOTH_WIDTH_RATIO$1);
4326
4379
  }
4327
- function createAntitankDitchUnderConstruction(positions, options = {}) {
4380
+ function createAntitankDitchUnderConstruction(positions, options = {}, textAmplifiers = {}) {
4328
4381
  const basePath = smoothedDitchBasePath(positions, options);
4329
4382
  const triangles = buildAntitankDitchTriangles(basePath, options);
4383
+ const baseLine = options.smooth ? basePath.map((point) => unproject(point[0], point[1])) : positions.map((position) => [position[0], position[1]]);
4384
+ const triangleLines = triangles.map((triangle) => triangle.map((point) => unproject(point[0], point[1])));
4385
+ const labels = [];
4386
+ pushHostileEndLabels(labels, basePath, textAmplifiers.N, options);
4330
4387
  return {
4331
4388
  type: "FeatureCollection",
4332
4389
  features: [{
@@ -4334,12 +4391,18 @@ function createAntitankDitchUnderConstruction(positions, options = {}) {
4334
4391
  properties: { part: "ditch" },
4335
4392
  geometry: {
4336
4393
  type: "MultiLineString",
4337
- coordinates: [options.smooth ? basePath.map((point) => unproject(point[0], point[1])) : positions.map((position) => [position[0], position[1]]), ...triangles.map((triangle) => triangle.map((point) => unproject(point[0], point[1])))]
4394
+ coordinates: [baseLine, ...triangleLines]
4338
4395
  }
4339
- }]
4396
+ }, ...labels]
4340
4397
  };
4341
4398
  }
4342
- function createAntitankDitchCompleted(positions, options = {}) {
4399
+ function createAntitankDitchCompleted(positions, options = {}, textAmplifiers = {}) {
4400
+ const basePath = smoothedDitchBasePath(positions, options);
4401
+ const polygons = buildAntitankDitchTriangles(basePath, options).map((triangle) => {
4402
+ return [[...triangle, triangle[0]].map((point) => unproject(point[0], point[1]))];
4403
+ });
4404
+ const labels = [];
4405
+ pushHostileEndLabels(labels, basePath, textAmplifiers.N, options);
4343
4406
  return {
4344
4407
  type: "FeatureCollection",
4345
4408
  features: [{
@@ -4350,11 +4413,9 @@ function createAntitankDitchCompleted(positions, options = {}) {
4350
4413
  },
4351
4414
  geometry: {
4352
4415
  type: "MultiPolygon",
4353
- coordinates: buildAntitankDitchTriangles(smoothedDitchBasePath(positions, options), options).map((triangle) => {
4354
- return [[...triangle, triangle[0]].map((point) => unproject(point[0], point[1]))];
4355
- })
4416
+ coordinates: polygons
4356
4417
  }
4357
- }]
4418
+ }, ...labels]
4358
4419
  };
4359
4420
  }
4360
4421
  const ANTITANK_DITCH_UNDER_CONSTRUCTION = defineControlMeasure({
@@ -4388,9 +4449,11 @@ const ANTITANK_WALL_METADATA = {
4388
4449
  value: "290204",
4389
4450
  minCoordinates: 2,
4390
4451
  geometry: "line",
4391
- geometryTypes: ["MultiLineString"],
4452
+ geometryTypes: ["MultiLineString", "Point"],
4392
4453
  drawRule: "Line1",
4393
- params: ANTITANK_WALL_PARAMS
4454
+ capturesLabelSize: true,
4455
+ params: ANTITANK_WALL_PARAMS,
4456
+ textAmplifiers: [HOSTILE_LINE_AMPLIFIER]
4394
4457
  };
4395
4458
  function generateAntitankWallPoints(projectedPoints, toothHeight, toothWidthRatio = DEFAULT_TOOTH_WIDTH_RATIO, toothSpacingRatio = DEFAULT_TOOTH_SPACING_RATIO) {
4396
4459
  if (projectedPoints.length < 2) return projectedPoints;
@@ -4423,12 +4486,16 @@ function generateAntitankWallPoints(projectedPoints, toothHeight, toothWidthRati
4423
4486
  }
4424
4487
  return wallPoints;
4425
4488
  }
4426
- function createAntitankWall(positions, options = {}) {
4489
+ function createAntitankWall(positions, options = {}, textAmplifiers = {}) {
4427
4490
  const toothHeight = calculateAntitankDitchHeight(options);
4428
4491
  const toothWidthRatio = options.toothWidthRatio ?? DEFAULT_TOOTH_WIDTH_RATIO;
4429
4492
  const toothSpacingRatio = options.toothSpacingRatio ?? DEFAULT_TOOTH_SPACING_RATIO;
4430
4493
  const projectedPoints = positions.map((position) => project(position[0], position[1]));
4431
4494
  const smoothedPath = smoothLineVerts(projectedPoints, options, 16);
4495
+ const basePath = options.smooth && projectedPoints.length >= 3 ? evenlySpacePath(smoothedPath, Math.max(EPSILON, toothWidthRatio) * toothHeight) : smoothedPath;
4496
+ const wallLine = generateAntitankWallPoints(basePath, toothHeight, toothWidthRatio, toothSpacingRatio).map((point) => unproject(point[0], point[1]));
4497
+ const labels = [];
4498
+ pushHostileEndLabels(labels, basePath, textAmplifiers.N, options);
4432
4499
  return {
4433
4500
  type: "FeatureCollection",
4434
4501
  features: [{
@@ -4436,9 +4503,9 @@ function createAntitankWall(positions, options = {}) {
4436
4503
  properties: { part: "wall" },
4437
4504
  geometry: {
4438
4505
  type: "MultiLineString",
4439
- coordinates: [generateAntitankWallPoints(options.smooth && projectedPoints.length >= 3 ? evenlySpacePath(smoothedPath, Math.max(EPSILON, toothWidthRatio) * toothHeight) : smoothedPath, toothHeight, toothWidthRatio, toothSpacingRatio).map((point) => unproject(point[0], point[1]))]
4506
+ coordinates: [wallLine]
4440
4507
  }
4441
- }]
4508
+ }, ...labels]
4442
4509
  };
4443
4510
  }
4444
4511
  const ANTITANK_WALL = defineControlMeasure({
@@ -5411,7 +5478,8 @@ const BOUNDARY_METADATA = {
5411
5478
  label: "Country (other side)",
5412
5479
  description: "Field AS1 — country code of the unit on the right-of-travel side.",
5413
5480
  maxLength: 8
5414
- }
5481
+ },
5482
+ HOSTILE_LINE_AMPLIFIER
5415
5483
  ]
5416
5484
  };
5417
5485
  /**
@@ -5436,7 +5504,8 @@ function createBoundary(positions, options = {}, textAmplifiers = {}) {
5436
5504
  const reps = resolveLabelRepetitions(labelRepetitions);
5437
5505
  const singleGroupPosition = clampLinePosition(labelPosition, DEFAULT_BOUNDARY_OPTIONS.labelPosition);
5438
5506
  const spec = resolveEchelon(echelon);
5439
- const labelSize = echelonSizePixels !== void 0 && metersPerPixel !== void 0 && metersPerPixel > 0 ? { textSizePixels: echelonSizePixels } : { textSizeMeters: h };
5507
+ const screenAnchored = echelonSizePixels !== void 0 && metersPerPixel !== void 0 && metersPerPixel > 0;
5508
+ const labelSize = screenAnchored ? { textSizePixels: echelonSizePixels } : { textSizeMeters: h };
5440
5509
  const rawVerts = positions.map((p) => project(p[0], p[1]));
5441
5510
  const verts = smooth ? catmullRom(rawVerts, normalizeSmoothResolution$2(smoothResolution, DEFAULT_SMOOTH_RESOLUTION$4)) : rawVerts;
5442
5511
  const glyphStrokes = [];
@@ -5499,6 +5568,15 @@ function createBoundary(positions, options = {}, textAmplifiers = {}) {
5499
5568
  labelSize
5500
5569
  }, units);
5501
5570
  }
5571
+ const hostileLabelOptions = screenAnchored ? {
5572
+ labelSizePixels: echelonSizePixels,
5573
+ metersPerPixel,
5574
+ labelPadding
5575
+ } : {
5576
+ labelSize: h,
5577
+ labelPadding
5578
+ };
5579
+ pushHostileEndLabels(labelFeatures, verts, textAmplifiers.N, hostileLabelOptions);
5502
5580
  const boundaryCoords = buildGappedLine(verts, gaps);
5503
5581
  const features = [];
5504
5582
  if (boundaryCoords.length > 0) features.push({
@@ -5598,18 +5676,19 @@ const LIGHT_LINE_METADATA = {
5598
5676
  max: 2,
5599
5677
  step: .05
5600
5678
  }
5601
- ]
5679
+ ],
5680
+ textAmplifiers: [HOSTILE_LINE_AMPLIFIER]
5602
5681
  };
5603
5682
  /**
5604
5683
  * Creates a Light line control measure: a polyline through `positions`
5605
5684
  * labeled "LL" above the line near each end.
5606
5685
  */
5607
- function createLightLine(positions, options = {}) {
5686
+ function createLightLine(positions, options = {}, textAmplifiers = {}) {
5608
5687
  return fixedLabelLineFeatures(positions, {
5609
5688
  part: "light-line",
5610
5689
  placement: "above",
5611
5690
  ...options
5612
- }, "LL");
5691
+ }, "LL", textAmplifiers.N);
5613
5692
  }
5614
5693
  const LIGHT_LINE = defineControlMeasure({
5615
5694
  metadata: LIGHT_LINE_METADATA,
@@ -5693,7 +5772,8 @@ const ENGINEER_WORK_LINE_METADATA = {
5693
5772
  label: "Country (other side)",
5694
5773
  description: "Field AS1 — country code of the engineer unit on the right-of-travel side.",
5695
5774
  maxLength: 8
5696
- }
5775
+ },
5776
+ HOSTILE_LINE_AMPLIFIER
5697
5777
  ]
5698
5778
  };
5699
5779
  /** Ratio of resolved label height used as the center label group's perpendicular offset. */
@@ -5711,7 +5791,7 @@ function createEngineerWorkLine(positions, options = {}, textAmplifiers = {}) {
5711
5791
  part: "engineer-work-line",
5712
5792
  placement: "above",
5713
5793
  ...options
5714
- }, "EWL").features];
5794
+ }, "EWL", textAmplifiers.N).features];
5715
5795
  const { segments, totalLength } = polylineSegments(smoothLineVerts(positions.map((p) => project(p[0], p[1])), options, 12));
5716
5796
  const frame = pointAlongPolyline(segments, totalLength, .5);
5717
5797
  if (frame) {
@@ -5828,7 +5908,8 @@ const GENERIC_C2_LINE_METADATA = {
5828
5908
  label: "Effective to (DTG)",
5829
5909
  description: "Field W1 — date-time group the line ceases to be effective, shown below it near each end.",
5830
5910
  maxLength: 16
5831
- }
5911
+ },
5912
+ HOSTILE_LINE_AMPLIFIER
5832
5913
  ]
5833
5914
  };
5834
5915
  /**
@@ -5856,7 +5937,7 @@ function createGenericC2Line(positions, options = {}, textAmplifiers = {}) {
5856
5937
  const above = [textAmplifiers.H, textAmplifiers.T].filter((v) => Boolean(v)).join(" ");
5857
5938
  const below = [textAmplifiers.W, textAmplifiers.W1].filter((v) => Boolean(v)).join(" - ");
5858
5939
  const trimmedPhaseLineName = phaseLineName?.trim();
5859
- if (above.length > 0 || below.length > 0 || trimmedPhaseLineName) {
5940
+ if (above.length > 0 || below.length > 0 || trimmedPhaseLineName || textAmplifiers.N) {
5860
5941
  const labelFeatures = [];
5861
5942
  if (above.length > 0 || below.length > 0) {
5862
5943
  const frames = aboveEndFrames(verts, sizeOptions);
@@ -5869,7 +5950,9 @@ function createGenericC2Line(positions, options = {}, textAmplifiers = {}) {
5869
5950
  if (below.length > 0) pushLabel(labelFeatures, vecAdd(base, vecScale(perp, -offset)), below, rotation, sizeProps, textAnchor);
5870
5951
  }
5871
5952
  }
5872
- if (trimmedPhaseLineName) pushEndLabels(labelFeatures, verts, includePrefix ? `PL ${trimmedPhaseLineName}` : trimmedPhaseLineName, sizeOptions);
5953
+ const nameText = phaseLineLabelText(trimmedPhaseLineName, includePrefix);
5954
+ if (nameText) pushEndLabels(labelFeatures, verts, nameText, sizeOptions);
5955
+ pushHostileEndLabels(labelFeatures, verts, textAmplifiers.N, sizeOptions, nameText);
5873
5956
  features.push(...labelFeatures);
5874
5957
  }
5875
5958
  return {
@@ -8442,8 +8525,9 @@ const FLOT_METADATA = {
8442
8525
  value: "140100",
8443
8526
  minCoordinates: 2,
8444
8527
  geometry: "line",
8445
- geometryTypes: ["LineString"],
8528
+ geometryTypes: ["LineString", "Point"],
8446
8529
  drawRule: "Line1",
8530
+ capturesLabelSize: true,
8447
8531
  params: [
8448
8532
  ...SMOOTH_LINE_PARAMS,
8449
8533
  {
@@ -8466,6 +8550,7 @@ const FLOT_METADATA = {
8466
8550
  step: 1,
8467
8551
  unit: "m"
8468
8552
  },
8553
+ LINE_LABEL_PADDING_PARAM,
8469
8554
  {
8470
8555
  key: "arcSegments",
8471
8556
  label: "Arc segments",
@@ -8475,7 +8560,8 @@ const FLOT_METADATA = {
8475
8560
  max: 32,
8476
8561
  step: 2
8477
8562
  }
8478
- ]
8563
+ ],
8564
+ textAmplifiers: [HOSTILE_LINE_AMPLIFIER]
8479
8565
  };
8480
8566
  /**
8481
8567
  * Generates points for a true semicircle arc along a segment.
@@ -8559,7 +8645,7 @@ function processSegment(p1, p2, radius, arcSegments, isFirstSegment) {
8559
8645
  * );
8560
8646
  * ```
8561
8647
  */
8562
- function createFLOT(positions, options = {}) {
8648
+ function createFLOT(positions, options = {}, textAmplifiers = {}) {
8563
8649
  const { radius = DEFAULT_RADIUS, radiusPixels, metersPerPixel, arcSegments = DEFAULT_ARC_SEGMENTS, smooth = DEFAULT_FLOT_OPTIONS.smooth, smoothResolution = DEFAULT_FLOT_OPTIONS.smoothResolution } = options;
8564
8650
  let effectiveRadius = radius;
8565
8651
  if (radiusPixels !== void 0 && metersPerPixel !== void 0 && metersPerPixel > 0) effectiveRadius = radiusPixels * metersPerPixel;
@@ -8588,16 +8674,19 @@ function createFLOT(positions, options = {}) {
8588
8674
  const lastGenerated = allPoints[allPoints.length - 1];
8589
8675
  if (vecMag(vecSub(lastOriginal, lastGenerated)) > 1e-6) allPoints.push(lastOriginal);
8590
8676
  }
8677
+ const feature = {
8678
+ type: "Feature",
8679
+ properties: {},
8680
+ geometry: {
8681
+ type: "LineString",
8682
+ coordinates: allPoints.map((p) => unproject(p[0], p[1]))
8683
+ }
8684
+ };
8685
+ const labels = [];
8686
+ pushHostileEndLabels(labels, allPoints, textAmplifiers.N, options);
8591
8687
  return {
8592
8688
  type: "FeatureCollection",
8593
- features: [{
8594
- type: "Feature",
8595
- properties: {},
8596
- geometry: {
8597
- type: "LineString",
8598
- coordinates: allPoints.map((p) => unproject(p[0], p[1]))
8599
- }
8600
- }]
8689
+ features: [feature, ...labels]
8601
8690
  };
8602
8691
  }
8603
8692
  const FLOT = defineControlMeasure({
@@ -8651,7 +8740,7 @@ const PHASE_LINE_METADATA = {
8651
8740
  description: "Field T — the phase line's unique designation.",
8652
8741
  placeholder: "ECHO",
8653
8742
  maxLength: 21
8654
- }]
8743
+ }, HOSTILE_LINE_AMPLIFIER]
8655
8744
  };
8656
8745
  /**
8657
8746
  * Creates a Phase line control measure: a polyline through `positions`
@@ -8664,7 +8753,7 @@ function createPhaseLine(positions, options = {}, textAmplifiers = {}) {
8664
8753
  return fixedLabelLineFeatures(positions, {
8665
8754
  part: "phase-line",
8666
8755
  ...sizeOptions
8667
- }, text);
8756
+ }, text, textAmplifiers.N);
8668
8757
  }
8669
8758
  const PHASE_LINE = defineControlMeasure({
8670
8759
  metadata: PHASE_LINE_METADATA,
@@ -8724,18 +8813,19 @@ const HANDOVER_LINE_METADATA = {
8724
8813
  max: 2,
8725
8814
  step: .05
8726
8815
  }
8727
- ]
8816
+ ],
8817
+ textAmplifiers: [HOSTILE_LINE_AMPLIFIER]
8728
8818
  };
8729
8819
  /**
8730
8820
  * Creates a Handover line control measure: a polyline through `positions`
8731
8821
  * labeled "HOL" above the line near each end.
8732
8822
  */
8733
- function createHandoverLine(positions, options = {}) {
8823
+ function createHandoverLine(positions, options = {}, textAmplifiers = {}) {
8734
8824
  return fixedLabelLineFeatures(positions, {
8735
8825
  part: "handover-line",
8736
8826
  placement: "above",
8737
8827
  ...options
8738
- }, "HOL");
8828
+ }, "HOL", textAmplifiers.N);
8739
8829
  }
8740
8830
  const HANDOVER_LINE = defineControlMeasure({
8741
8831
  metadata: HANDOVER_LINE_METADATA,
@@ -8794,18 +8884,19 @@ const BATTLE_HANDOVER_LINE_METADATA = {
8794
8884
  max: 2,
8795
8885
  step: .05
8796
8886
  }
8797
- ]
8887
+ ],
8888
+ textAmplifiers: [HOSTILE_LINE_AMPLIFIER]
8798
8889
  };
8799
8890
  /**
8800
8891
  * Creates a Battle handover line control measure: a polyline through
8801
8892
  * `positions` labeled "BHL" above the line near each end.
8802
8893
  */
8803
- function createBattleHandoverLine(positions, options = {}) {
8894
+ function createBattleHandoverLine(positions, options = {}, textAmplifiers = {}) {
8804
8895
  return fixedLabelLineFeatures(positions, {
8805
8896
  part: "battle-handover-line",
8806
8897
  placement: "above",
8807
8898
  ...options
8808
- }, "BHL");
8899
+ }, "BHL", textAmplifiers.N);
8809
8900
  }
8810
8901
  const BATTLE_HANDOVER_LINE = defineControlMeasure({
8811
8902
  metadata: BATTLE_HANDOVER_LINE_METADATA,
@@ -8840,9 +8931,11 @@ const FORTIFIED_LINE_METADATA = {
8840
8931
  value: "290900",
8841
8932
  minCoordinates: 2,
8842
8933
  geometry: "line",
8843
- geometryTypes: ["LineString"],
8934
+ geometryTypes: ["LineString", "Point"],
8844
8935
  drawRule: "Line1",
8845
- params: FORTIFIED_PARAMS
8936
+ capturesLabelSize: true,
8937
+ params: FORTIFIED_PARAMS,
8938
+ textAmplifiers: [HOSTILE_LINE_AMPLIFIER]
8846
8939
  };
8847
8940
  /**
8848
8941
  * Generates points for a square wave "tooth" along a segment.
@@ -8950,20 +9043,24 @@ function generateFortifiedPoints(projectedPoints, effectiveSize) {
8950
9043
  * @param options - Configuration options for the graphic
8951
9044
  * @returns A GeoJSON FeatureCollection containing the castellated LineString
8952
9045
  */
8953
- function createFortifiedLine(positions, options = {}) {
9046
+ function createFortifiedLine(positions, options = {}, textAmplifiers = {}) {
8954
9047
  const { smooth = DEFAULT_FORTIFIED_LINE_OPTIONS.smooth, smoothResolution = DEFAULT_FORTIFIED_LINE_OPTIONS.smoothResolution } = options;
8955
9048
  const safeSize = calculateEffectiveSize(options);
8956
9049
  const projectedPoints = positions.map((p) => project(p[0], p[1]));
9050
+ const allPoints = generateFortifiedPoints(smooth ? evenlySpacePath(catmullRom(projectedPoints, normalizeSmoothResolution$2(smoothResolution, DEFAULT_SMOOTH_RESOLUTION$1)), 2 * safeSize) : projectedPoints, safeSize);
9051
+ const feature = {
9052
+ type: "Feature",
9053
+ properties: {},
9054
+ geometry: {
9055
+ type: "LineString",
9056
+ coordinates: allPoints.map((p) => unproject(p[0], p[1]))
9057
+ }
9058
+ };
9059
+ const labels = [];
9060
+ pushHostileEndLabels(labels, allPoints, textAmplifiers.N, options);
8957
9061
  return {
8958
9062
  type: "FeatureCollection",
8959
- features: [{
8960
- type: "Feature",
8961
- properties: {},
8962
- geometry: {
8963
- type: "LineString",
8964
- coordinates: generateFortifiedPoints(smooth ? evenlySpacePath(catmullRom(projectedPoints, normalizeSmoothResolution$2(smoothResolution, DEFAULT_SMOOTH_RESOLUTION$1)), 2 * safeSize) : projectedPoints, safeSize).map((p) => unproject(p[0], p[1]))
8965
- }
8966
- }]
9063
+ features: [feature, ...labels]
8967
9064
  };
8968
9065
  }
8969
9066
  const FORTIFIED_LINE = defineControlMeasure({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orbat-mapper/control-measures",
3
- "version": "0.2.0-alpha.18",
3
+ "version": "0.2.0-alpha.19",
4
4
  "description": "Library for drawing tactical graphics and control measures according to MIL-STD-2525 and APP-6 standards.",
5
5
  "license": "MIT",
6
6
  "author": "Orbat Mapper",