@orbat-mapper/control-measures 0.12.0 → 0.13.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.
package/README.md CHANGED
@@ -197,6 +197,7 @@ code.
197
197
  | <img src="media/minefield.svg" width="96" height="48" alt=""> | `minefield` | Minefield | `270701` |
198
198
  | <img src="media/minefield-dynamic.svg" width="96" height="48" alt=""> | `minefield-dynamic` | Minefield (Dynamic) | `270707` |
199
199
  | <img src="media/mined-area.svg" width="96" height="48" alt=""> | `mined-area` | Mined Area | `270800` |
200
+ | <img src="media/bridge-or-gap.svg" width="96" height="48" alt=""> | `bridge-or-gap` | Bridge or Gap | `271100` |
200
201
 
201
202
  ### Protection Lines
202
203
 
@@ -230,6 +231,8 @@ code.
230
231
  | <img src="media/seize.svg" width="96" height="48" alt=""> | `seize` | Seize | `342300` |
231
232
  | <img src="media/withdraw.svg" width="96" height="48" alt=""> | `withdraw` | Withdraw | `342400` |
232
233
  | <img src="media/withdraw-under-pressure.svg" width="96" height="48" alt=""> | `withdraw-under-pressure` | Withdraw Under Pressure | `342500` |
234
+ | <img src="media/envelopment.svg" width="96" height="48" alt=""> | `envelopment` | Envelopment | `343500` |
235
+ | <img src="media/infiltration.svg" width="96" height="48" alt=""> | `infiltration` | Infiltration | `343800` |
233
236
  | <img src="media/rearward-passage-of-lines.svg" width="96" height="48" alt=""> | `rearward-passage-of-lines` | Rearward Passage of Lines | `344200` |
234
237
  | <img src="media/disengage.svg" width="96" height="48" alt=""> | `disengage` | Disengage | `344400` |
235
238
 
@@ -805,6 +805,22 @@ declare function createEngineerWorkLine(positions: Position[], options?: Enginee
805
805
  //#region src/generators/cm11-command-control-lines/generic-c2-line.d.ts
806
806
  /** Configuration options for the Generic command and control line. */
807
807
  interface GenericC2LineOptions extends LineLabelOptions, SmoothLineOptions {
808
+ /** Field B echelon glyph. Empty, `"none"`, or unknown renders no glyph. @default "none" */
809
+ echelon?: string;
810
+ /** Echelon glyph height in meters (ground-anchored). @default 750 */
811
+ echelonSize?: number;
812
+ /** Echelon glyph height in screen pixels (screen-anchored). @default 16 */
813
+ echelonSizePixels?: number;
814
+ /** Gap on each side of the echelon glyph, as a ratio of its height. @default 0.3 */
815
+ echelonPadding?: number;
816
+ /** Number of echelon glyphs distributed along the whole line. @default 1 */
817
+ labelRepetitions?: number;
818
+ /** Spread of repeated echelons around the midpoint. @default 1 */
819
+ labelSpacing?: number;
820
+ /** Position of a single echelon along the line by cumulative arc length. @default 0.5 */
821
+ labelPosition?: number;
822
+ /** Orient echelons along the line or using Boundary's standard placement. @default "along" */
823
+ labelOrientation?: "along" | "standard";
808
824
  /**
809
825
  * Optional phase line naming: renders `PL <name>` just beyond each end of
810
826
  * the line, additive to the H/T/W/W1 amplifier labels. Empty or
@@ -831,11 +847,17 @@ declare const DEFAULT_GENERIC_C2_LINE_OPTIONS: GenericC2LineOptions;
831
847
  * (inset from the tip, anchored toward the line's interior), one at
832
848
  * `base + perp·offset` and the other at `base − perp·offset`.
833
849
  */
834
- declare function createGenericC2Line(positions: Position[], options?: GenericC2LineOptions, textAmplifiers?: CanonicalTextAmplifiers, context?: ControlMeasureGeneratorContext): FeatureCollection<LineString | Point>;
850
+ declare function createGenericC2Line(positions: Position[], options?: GenericC2LineOptions, textAmplifiers?: CanonicalTextAmplifiers, context?: ControlMeasureGeneratorContext): FeatureCollection<LineString | MultiLineString | MultiPolygon | Point>;
835
851
  //#endregion
836
852
  //#region src/internal/area-labels.d.ts
837
853
  /** Shared placement options for the centered-label area measures. */
838
854
  interface AreaLabelOptions extends LabelSizeOptions {
855
+ /**
856
+ * Render a doctrinal label prefix and Field T on separate centered lines.
857
+ * Areas without a prefix, or without Field T, keep a single-line label.
858
+ * @default false
859
+ */
860
+ multilineLabel?: boolean;
839
861
  /**
840
862
  * Extra row leading (and ENY inset), as a ratio of the label's resolved
841
863
  * text height, like the labeled line measures' own `labelPadding`.
package/dist/index.d.mts CHANGED
@@ -1,3 +1,3 @@
1
- import { $ as CONTROL_MEASURE_METADATA, $i as ControlMeasurePaintCapability, $n as DEFAULT_ATTACK_HELICOPTER_OPTIONS, $r as StyleHints, $t as DEFAULT_DISRUPT_MISSION_TASK_OPTIONS, A as BaselineFrame, Ai as sphericalBearing, An as DEFAULT_LIMIT_OF_ADVANCE_OPTIONS, Ar as AreaOfOperationsOptions, At as FortifiedAreaOptions, B as toSimpleStyle, Bi as DEFAULT_LABEL_SIZE_CLAMP_CSS_PIXELS, Bn as BridgeheadLineOptions, Br as DEFAULT_ASSEMBLY_AREA_OPTIONS, Bt as WithdrawOptions, C as area27DrawRule, Ci as EngineerWorkLineOptions, Cn as DEFAULT_PROBABLE_LINE_OF_DEPLOYMENT_OPTIONS, Cr as DEFAULT_CLASSIC_ARROW_OPTIONS, Ct as BlockOptions, D as getMidpointPerpendicularSignedDistance, Di as Point2D, Dn as LineOfDepartureContactOptions, Dr as MainAttackOptions, Dt as DEFAULT_FRONTAL_ATTACK_OPTIONS, E as createMidpointPerpendicularDrawRule, Ei as LabelSizeOptions, En as DEFAULT_LINE_OF_DEPARTURE_CONTACT_OPTIONS, Er as DEFAULT_MAIN_ATTACK_OPTIONS, Et as TurningMovementOptions, F as EPSILON, Fi as ControlMeasureOptionHandle, Fn as HandoverLineOptions, Fr as DEFAULT_LANDING_ZONE_OPTIONS, Ft as AntitankDitchOptions, G as foldsBoxTransformOptions, Gi as DEFAULT_STROKE_WIDTH_CSS_PIXELS, Gn as PhaseLineOptions, Gr as AreaDefenseOptions, Gt as DEFAULT_RETIRE_OPTIONS, H as dragControlMeasureOptionHandle, Hi as DEFAULT_LINE_JOIN, Hn as DEFAULT_FORWARD_EDGE_OF_BATTLE_AREA_OPTIONS, Hr as MobileDefenseOptions, Ht as SeizeOptions, I as getMetersPerPixel, Ii as ControlMeasureOptionHandleDragEvent, In as DEFAULT_RELEASE_LINE_OPTIONS, Ir as LandingZoneOptions, It as DEFAULT_ANTITANK_DITCH_OPTIONS, J as renderControlMeasure, Ji as MeasuredText, Jn as AttackByFireOptions, Jr as EncirclementOptions, Jt as RearwardPassageOfLinesOptions, K as freezeOrientationOptions, Ki as LogicalTextStyle, Kn as DEFAULT_FLOT_OPTIONS, Kr as DEFAULT_AREA_DEFENSE_OPTIONS, Kt as RetireOptions, L as roundToFixed, Li as ControlMeasureOptionHandles, Ln as ReleaseLineOptions, Lr as DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, Lt as DEFAULT_WITHDRAW_UNDER_PRESSURE_OPTIONS, M as BaselineFrameOptions, Mi as BoundaryOptions, Mn as BattleHandoverLineOptions, Mr as DEFAULT_PICKUP_ZONE_OPTIONS, Mt as FortifiedLineOptions, N as BaselineFrameOrigin, Ni as DEFAULT_BOUNDARY_OPTIONS, Nn as DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, Nr as PickupZoneOptions, Nt as AntitankWallOptions, O as pointOnMidpointPerpendicularAxis, Oi as haversineDistance, On as DEFAULT_LINE_OF_DEPARTURE_OPTIONS, Or as calculateMetrics, Ot as FrontalAttackOptions, P as createBaselineFrame, Pi as BoxTransformDelta, Pn as DEFAULT_HANDOVER_LINE_OPTIONS, Pr as MineType, Pt as DEFAULT_ANTITANK_WALL_OPTIONS, Q as CONTROL_MEASURE_IDS, Qi as ControlMeasureMetadata, Qn as AttackHelicopterOptions, Qr as FeaturePartProps, Qt as GuardOptions, R as SimpleStyleProps, Ri as ControlMeasureRenderContext, Rn as DEFAULT_HOLDING_LINE_OPTIONS, Rr as JointTacticalActionAreaOptions, Rt as WithdrawUnderPressureOptions, S as containDrawRule, Si as DEFAULT_ENGINEER_WORK_LINE_OPTIONS, Sn as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, Sr as ClassicArrowOptions, St as DisruptOptions, T as computeDefaultMidpointPerpendicularPoint, Ti as LightLineOptions, Tn as ProbableLineOfDeploymentOptions, Tr as SupportingAttackOptions, Tt as DEFAULT_TURNING_MOVEMENT_OPTIONS, U as getControlMeasureOptionHandles, Ui as DEFAULT_PORTRAYAL, Un as ForwardEdgeOfBattleAreaOptions, Ur as DEFAULT_ENGAGEMENT_AREA_OPTIONS, Ut as DEFAULT_SCREEN_OPTIONS, V as resolveStyleHints, Vi as DEFAULT_LINE_CAP, Vn as DEFAULT_BRIDGEHEAD_LINE_OPTIONS, Vr as DEFAULT_MOBILE_DEFENSE_OPTIONS, Vt as DEFAULT_SEIZE_OPTIONS, W as applyBoxTransformOptions, Wi as DEFAULT_STROKE_DASH_CSS_PIXELS, Wn as DEFAULT_PHASE_LINE_OPTIONS, Wr as EngagementAreaOptions, Wt as ScreenOptions, X as cloneControlMeasure, Xi as ControlMeasureGeometry, Xn as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, Xr as FinalProtectiveFireOptions, Xt as PenetrateOptions, Y as ControlMeasure, Yi as ControlMeasureFillCapability, Yn as DEFAULT_ATTACK_BY_FIRE_OPTIONS, Yr as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, Yt as DEFAULT_PENETRATE_OPTIONS, Z as isKind, Zi as ControlMeasureGeometryType, Zn as SupportByFireOptions, Zr as ControlMeasureRender, Zt as DEFAULT_GUARD_OPTIONS, _ as point12DrawRule, _a as canonicalTextAmplifierKey, _i as DEFAULT_CONTAIN_OPTIONS, _n as BypassOptions, _r as GenericLineOptions, _t as DEFAULT_FIX_MISSION_TASK_OPTIONS, a as axis1DrawRule, aa as parameterPresentationTierRank, ai as PrincipalDirectionOfFireOptions, an as CoverOptions, ar as RadarSearchDoctrineOptions, at as getDefaultOptions, b as disruptDrawRule, ba as AnchorTransformEvent, bi as DEFAULT_GENERIC_C2_LINE_OPTIONS, bn as DEFAULT_BREACH_OPTIONS, br as DEFAULT_BLOCK_ARROW_OPTIONS, bt as FixOptions, c as line26DrawRule, ca as AmplifierPlacement, ci as DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS, cn as TacticalArrowOptions, cr as DEFAULT_GENERIC_SECTOR_OPTIONS, ct as ObstacleBypassImpossibleOptions, d as turnDrawRule, da as GeneratedLabelKey, di as DirectionOfAttackAviationOptions, dn as CounterattackOptions, dr as GenericCircleOptions, dt as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, ea as PARAMETER_PRESENTATION_TIERS, ei as controlMeasureIdFromFeature, en as DisruptMissionTaskOptions, er as AirborneAttackOptions, et as ControlMeasureId, f as line1DrawRule, fa as LabelPlacementOverride, fi as DEFAULT_RETAIN_OPTIONS, fn as DEFAULT_COUNTERATTACK_OPTIONS, fr as DEFAULT_GENERIC_RECTANGLE_OPTIONS, ft as ObstacleBypassEasyOptions, g as staticPointDrawRule, ga as TextAmplifiers, gi as ContainOptions, gn as DEFAULT_CANALIZE_OPTIONS, gr as DEFAULT_GENERIC_LINE_OPTIONS, gt as TurnOptions, h as dynamicPointDrawRule, ha as TextAmplifierKey, hi as StrongPointOptions, hn as CanalizeOptions, hr as GenericPolygonOptions, ht as DEFAULT_TURN_OPTIONS, i as rectangleDrawRule, ia as TextAmplifierDescriptor, ii as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, in as DelayOptions, ir as RADAR_SEARCH_DOCTRINE_STROKE_COLOR, it as getControlMeasureMetadataByValue, j as BaselineFrameNormal, ji as unproject, jn as LimitOfAdvanceOptions, jr as DEFAULT_AREA_OF_OPERATIONS_OPTIONS, jt as DEFAULT_FORTIFIED_LINE_OPTIONS, k as snapToMidpointPerpendicular, ki as project, kn as LineOfDepartureOptions, kr as computeInitialWidthPoint, kt as DEFAULT_FORTIFIED_AREA_OPTIONS, l as line24DrawRule, la as AmplifierPlacements, li as DirectionOfMainAttackOptions, ln as CounterattackByFireOptions, lr as GenericSectorOptions, lt as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, m as attackByFireDrawRule, ma as TextAmplifierField, mi as DEFAULT_STRONG_POINT_OPTIONS, mn as DEFAULT_CLEAR_OPTIONS, mr as DEFAULT_GENERIC_POLYGON_OPTIONS, mt as MinefieldOptions, n as DEFAULT_AMBUSH_OPTIONS, na as ParameterPresentationTier, ni as SECONDARY_DIRECTION_OF_FIRE_DASH, nn as DisengageOptions, nr as DEFAULT_RADAR_SEARCH_DOCTRINE_OPTIONS, nt as OptionsByKind, o as supportByFireDrawRule, oa as resolveParameterPresentationTier, oi as DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS, on as DEFAULT_COVER_OPTIONS, or as DEFAULT_GENERIC_TEXT_OPTIONS, ot as listControlMeasureMetadata, p as ambushDrawRule, pa as TEXT_AMPLIFIER_FIELDS, pi as RetainOptions, pn as ClearOptions, pr as GenericRectangleOptions, pt as DEFAULT_MINEFIELD_OPTIONS, q as RenderOptions, qi as MeasureTextRequest, qn as FLOTOptions, qr as DEFAULT_ENCIRCLEMENT_OPTIONS, qt as DEFAULT_REARWARD_PASSAGE_OF_LINES_OPTIONS, r as sectorDrawRule, ra as ParameterSemanticRole, ri as SecondaryDirectionOfFireOptions, rn as DEFAULT_DELAY_OPTIONS, rr as RADAR_SEARCH_DOCTRINE_FILL_COLOR, rt as getControlMeasureMetadata, s as line27DrawRule, sa as resolveParameterSemanticRole, si as DirectionOfSupportingAttackOptions, sn as DEFAULT_TACTICAL_ARROW_OPTIONS, sr as GenericTextOptions, st as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, t as AmbushOptions, ta as ParamDescriptor, ti as DEFAULT_SECONDARY_DIRECTION_OF_FIRE_OPTIONS, tn as DEFAULT_DISENGAGE_OPTIONS, tr as DEFAULT_AIRBORNE_ATTACK_OPTIONS, tt as ControlMeasureKind, u as line23DrawRule, ua as CanonicalTextAmplifiers, ui as DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS, un as DEFAULT_COUNTERATTACK_BY_FIRE_OPTIONS, ur as DEFAULT_GENERIC_CIRCLE_OPTIONS, ut as ObstacleBypassDifficultOptions, v as penetrateDrawRule, va as normalizeTextAmplifiers, vi as BattlePositionOptions, vn as DEFAULT_BYPASS_OPTIONS, vr as BlockArrowHeadStyle, vt as FixMissionTaskOptions, w as MidpointPerpendicularDrawRuleOptions, wi as DEFAULT_LIGHT_LINE_OPTIONS, wn as PROBABLE_LINE_OF_DEPLOYMENT_DASH, wr as DEFAULT_SUPPORTING_ATTACK_OPTIONS, wt as DEFAULT_BLOCK_OPTIONS, x as blockDrawRule, xa as ControlMeasureDrawRule, xi as GenericC2LineOptions, xn as BlockMissionTaskOptions, xr as ClassicArrowHeadStyle, xt as DEFAULT_DISRUPT_OPTIONS, y as centerRadiusDrawRule, ya as resolveAmplifierPlacement, yi as DEFAULT_BATTLE_POSITION_OPTIONS, yn as BreachOptions, yr as BlockArrowOptions, yt as DEFAULT_FIX_OPTIONS, z as SimpleStyleRender, zi as DEFAULT_LABEL_HEIGHT_CSS_PIXELS, zn as HoldingLineOptions, zr as AssemblyAreaOptions, zt as DEFAULT_WITHDRAW_OPTIONS } from "./index-IeI0ELGA.mjs";
1
+ import { $ as CONTROL_MEASURE_METADATA, $i as ControlMeasurePaintCapability, $n as DEFAULT_ATTACK_HELICOPTER_OPTIONS, $r as StyleHints, $t as DEFAULT_DISRUPT_MISSION_TASK_OPTIONS, A as BaselineFrame, Ai as sphericalBearing, An as DEFAULT_LIMIT_OF_ADVANCE_OPTIONS, Ar as AreaOfOperationsOptions, At as FortifiedAreaOptions, B as toSimpleStyle, Bi as DEFAULT_LABEL_SIZE_CLAMP_CSS_PIXELS, Bn as BridgeheadLineOptions, Br as DEFAULT_ASSEMBLY_AREA_OPTIONS, Bt as WithdrawOptions, C as area27DrawRule, Ci as EngineerWorkLineOptions, Cn as DEFAULT_PROBABLE_LINE_OF_DEPLOYMENT_OPTIONS, Cr as DEFAULT_CLASSIC_ARROW_OPTIONS, Ct as BlockOptions, D as getMidpointPerpendicularSignedDistance, Di as Point2D, Dn as LineOfDepartureContactOptions, Dr as MainAttackOptions, Dt as DEFAULT_FRONTAL_ATTACK_OPTIONS, E as createMidpointPerpendicularDrawRule, Ei as LabelSizeOptions, En as DEFAULT_LINE_OF_DEPARTURE_CONTACT_OPTIONS, Er as DEFAULT_MAIN_ATTACK_OPTIONS, Et as TurningMovementOptions, F as EPSILON, Fi as ControlMeasureOptionHandle, Fn as HandoverLineOptions, Fr as DEFAULT_LANDING_ZONE_OPTIONS, Ft as AntitankDitchOptions, G as foldsBoxTransformOptions, Gi as DEFAULT_STROKE_WIDTH_CSS_PIXELS, Gn as PhaseLineOptions, Gr as AreaDefenseOptions, Gt as DEFAULT_RETIRE_OPTIONS, H as dragControlMeasureOptionHandle, Hi as DEFAULT_LINE_JOIN, Hn as DEFAULT_FORWARD_EDGE_OF_BATTLE_AREA_OPTIONS, Hr as MobileDefenseOptions, Ht as SeizeOptions, I as getMetersPerPixel, Ii as ControlMeasureOptionHandleDragEvent, In as DEFAULT_RELEASE_LINE_OPTIONS, Ir as LandingZoneOptions, It as DEFAULT_ANTITANK_DITCH_OPTIONS, J as renderControlMeasure, Ji as MeasuredText, Jn as AttackByFireOptions, Jr as EncirclementOptions, Jt as RearwardPassageOfLinesOptions, K as freezeOrientationOptions, Ki as LogicalTextStyle, Kn as DEFAULT_FLOT_OPTIONS, Kr as DEFAULT_AREA_DEFENSE_OPTIONS, Kt as RetireOptions, L as roundToFixed, Li as ControlMeasureOptionHandles, Ln as ReleaseLineOptions, Lr as DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, Lt as DEFAULT_WITHDRAW_UNDER_PRESSURE_OPTIONS, M as BaselineFrameOptions, Mi as BoundaryOptions, Mn as BattleHandoverLineOptions, Mr as DEFAULT_PICKUP_ZONE_OPTIONS, Mt as FortifiedLineOptions, N as BaselineFrameOrigin, Ni as DEFAULT_BOUNDARY_OPTIONS, Nn as DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, Nr as PickupZoneOptions, Nt as AntitankWallOptions, O as pointOnMidpointPerpendicularAxis, Oi as haversineDistance, On as DEFAULT_LINE_OF_DEPARTURE_OPTIONS, Or as calculateMetrics, Ot as FrontalAttackOptions, P as createBaselineFrame, Pi as BoxTransformDelta, Pn as DEFAULT_HANDOVER_LINE_OPTIONS, Pr as MineType, Pt as DEFAULT_ANTITANK_WALL_OPTIONS, Q as CONTROL_MEASURE_IDS, Qi as ControlMeasureMetadata, Qn as AttackHelicopterOptions, Qr as FeaturePartProps, Qt as GuardOptions, R as SimpleStyleProps, Ri as ControlMeasureRenderContext, Rn as DEFAULT_HOLDING_LINE_OPTIONS, Rr as JointTacticalActionAreaOptions, Rt as WithdrawUnderPressureOptions, S as containDrawRule, Si as DEFAULT_ENGINEER_WORK_LINE_OPTIONS, Sn as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, Sr as ClassicArrowOptions, St as DisruptOptions, T as computeDefaultMidpointPerpendicularPoint, Ti as LightLineOptions, Tn as ProbableLineOfDeploymentOptions, Tr as SupportingAttackOptions, Tt as DEFAULT_TURNING_MOVEMENT_OPTIONS, U as getControlMeasureOptionHandles, Ui as DEFAULT_PORTRAYAL, Un as ForwardEdgeOfBattleAreaOptions, Ur as DEFAULT_ENGAGEMENT_AREA_OPTIONS, Ut as DEFAULT_SCREEN_OPTIONS, V as resolveStyleHints, Vi as DEFAULT_LINE_CAP, Vn as DEFAULT_BRIDGEHEAD_LINE_OPTIONS, Vr as DEFAULT_MOBILE_DEFENSE_OPTIONS, Vt as DEFAULT_SEIZE_OPTIONS, W as applyBoxTransformOptions, Wi as DEFAULT_STROKE_DASH_CSS_PIXELS, Wn as DEFAULT_PHASE_LINE_OPTIONS, Wr as EngagementAreaOptions, Wt as ScreenOptions, X as cloneControlMeasure, Xi as ControlMeasureGeometry, Xn as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, Xr as FinalProtectiveFireOptions, Xt as PenetrateOptions, Y as ControlMeasure, Yi as ControlMeasureFillCapability, Yn as DEFAULT_ATTACK_BY_FIRE_OPTIONS, Yr as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, Yt as DEFAULT_PENETRATE_OPTIONS, Z as isKind, Zi as ControlMeasureGeometryType, Zn as SupportByFireOptions, Zr as ControlMeasureRender, Zt as DEFAULT_GUARD_OPTIONS, _ as point12DrawRule, _a as canonicalTextAmplifierKey, _i as DEFAULT_CONTAIN_OPTIONS, _n as BypassOptions, _r as GenericLineOptions, _t as DEFAULT_FIX_MISSION_TASK_OPTIONS, a as axis1DrawRule, aa as parameterPresentationTierRank, ai as PrincipalDirectionOfFireOptions, an as CoverOptions, ar as RadarSearchDoctrineOptions, at as getDefaultOptions, b as disruptDrawRule, ba as AnchorTransformEvent, bi as DEFAULT_GENERIC_C2_LINE_OPTIONS, bn as DEFAULT_BREACH_OPTIONS, br as DEFAULT_BLOCK_ARROW_OPTIONS, bt as FixOptions, c as line26DrawRule, ca as AmplifierPlacement, ci as DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS, cn as TacticalArrowOptions, cr as DEFAULT_GENERIC_SECTOR_OPTIONS, ct as ObstacleBypassImpossibleOptions, d as turnDrawRule, da as GeneratedLabelKey, di as DirectionOfAttackAviationOptions, dn as CounterattackOptions, dr as GenericCircleOptions, dt as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, ea as PARAMETER_PRESENTATION_TIERS, ei as controlMeasureIdFromFeature, en as DisruptMissionTaskOptions, er as AirborneAttackOptions, et as ControlMeasureId, f as line1DrawRule, fa as LabelPlacementOverride, fi as DEFAULT_RETAIN_OPTIONS, fn as DEFAULT_COUNTERATTACK_OPTIONS, fr as DEFAULT_GENERIC_RECTANGLE_OPTIONS, ft as ObstacleBypassEasyOptions, g as staticPointDrawRule, ga as TextAmplifiers, gi as ContainOptions, gn as DEFAULT_CANALIZE_OPTIONS, gr as DEFAULT_GENERIC_LINE_OPTIONS, gt as TurnOptions, h as dynamicPointDrawRule, ha as TextAmplifierKey, hi as StrongPointOptions, hn as CanalizeOptions, hr as GenericPolygonOptions, ht as DEFAULT_TURN_OPTIONS, i as rectangleDrawRule, ia as TextAmplifierDescriptor, ii as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, in as DelayOptions, ir as RADAR_SEARCH_DOCTRINE_STROKE_COLOR, it as getControlMeasureMetadataByValue, j as BaselineFrameNormal, ji as unproject, jn as LimitOfAdvanceOptions, jr as DEFAULT_AREA_OF_OPERATIONS_OPTIONS, jt as DEFAULT_FORTIFIED_LINE_OPTIONS, k as snapToMidpointPerpendicular, ki as project, kn as LineOfDepartureOptions, kr as computeInitialWidthPoint, kt as DEFAULT_FORTIFIED_AREA_OPTIONS, l as line24DrawRule, la as AmplifierPlacements, li as DirectionOfMainAttackOptions, ln as CounterattackByFireOptions, lr as GenericSectorOptions, lt as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, m as attackByFireDrawRule, ma as TextAmplifierField, mi as DEFAULT_STRONG_POINT_OPTIONS, mn as DEFAULT_CLEAR_OPTIONS, mr as DEFAULT_GENERIC_POLYGON_OPTIONS, mt as MinefieldOptions, n as DEFAULT_AMBUSH_OPTIONS, na as ParameterPresentationTier, ni as SECONDARY_DIRECTION_OF_FIRE_DASH, nn as DisengageOptions, nr as DEFAULT_RADAR_SEARCH_DOCTRINE_OPTIONS, nt as OptionsByKind, o as supportByFireDrawRule, oa as resolveParameterPresentationTier, oi as DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS, on as DEFAULT_COVER_OPTIONS, or as DEFAULT_GENERIC_TEXT_OPTIONS, ot as listControlMeasureMetadata, p as ambushDrawRule, pa as TEXT_AMPLIFIER_FIELDS, pi as RetainOptions, pn as ClearOptions, pr as GenericRectangleOptions, pt as DEFAULT_MINEFIELD_OPTIONS, q as RenderOptions, qi as MeasureTextRequest, qn as FLOTOptions, qr as DEFAULT_ENCIRCLEMENT_OPTIONS, qt as DEFAULT_REARWARD_PASSAGE_OF_LINES_OPTIONS, r as sectorDrawRule, ra as ParameterSemanticRole, ri as SecondaryDirectionOfFireOptions, rn as DEFAULT_DELAY_OPTIONS, rr as RADAR_SEARCH_DOCTRINE_FILL_COLOR, rt as getControlMeasureMetadata, s as line27DrawRule, sa as resolveParameterSemanticRole, si as DirectionOfSupportingAttackOptions, sn as DEFAULT_TACTICAL_ARROW_OPTIONS, sr as GenericTextOptions, st as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, t as AmbushOptions, ta as ParamDescriptor, ti as DEFAULT_SECONDARY_DIRECTION_OF_FIRE_OPTIONS, tn as DEFAULT_DISENGAGE_OPTIONS, tr as DEFAULT_AIRBORNE_ATTACK_OPTIONS, tt as ControlMeasureKind, u as line23DrawRule, ua as CanonicalTextAmplifiers, ui as DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS, un as DEFAULT_COUNTERATTACK_BY_FIRE_OPTIONS, ur as DEFAULT_GENERIC_CIRCLE_OPTIONS, ut as ObstacleBypassDifficultOptions, v as penetrateDrawRule, va as normalizeTextAmplifiers, vi as BattlePositionOptions, vn as DEFAULT_BYPASS_OPTIONS, vr as BlockArrowHeadStyle, vt as FixMissionTaskOptions, w as MidpointPerpendicularDrawRuleOptions, wi as DEFAULT_LIGHT_LINE_OPTIONS, wn as PROBABLE_LINE_OF_DEPLOYMENT_DASH, wr as DEFAULT_SUPPORTING_ATTACK_OPTIONS, wt as DEFAULT_BLOCK_OPTIONS, x as blockDrawRule, xa as ControlMeasureDrawRule, xi as GenericC2LineOptions, xn as BlockMissionTaskOptions, xr as ClassicArrowHeadStyle, xt as DEFAULT_DISRUPT_OPTIONS, y as centerRadiusDrawRule, ya as resolveAmplifierPlacement, yi as DEFAULT_BATTLE_POSITION_OPTIONS, yn as BreachOptions, yr as BlockArrowOptions, yt as DEFAULT_FIX_OPTIONS, z as SimpleStyleRender, zi as DEFAULT_LABEL_HEIGHT_CSS_PIXELS, zn as HoldingLineOptions, zr as AssemblyAreaOptions, zt as DEFAULT_WITHDRAW_OPTIONS } from "./index-BzMR6vIE.mjs";
2
2
  import { a as PatternId, c as PatternPoint, d as ControlMeasureStyle, f as FillPattern, i as NON_SOLID_FILL_PATTERNS, l as PatternStroke, n as FillPatternCommand, o as PatternPaint, r as FillPatternDefinition, s as PatternPathOperation, t as FILL_PATTERN_DEFINITIONS, u as getFillPatternDefinition } from "./patterns-CcQmmOuJ.mjs";
3
3
  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 BoxTransformDelta, type BreachOptions, type BridgeheadLineOptions, type BypassOptions, CONTROL_MEASURE_IDS, CONTROL_MEASURE_METADATA, type CanalizeOptions, type CanonicalTextAmplifiers, type ClassicArrowHeadStyle, type ClassicArrowOptions, type ClearOptions, type ContainOptions, type ControlMeasure, type ControlMeasureDrawRule, type ControlMeasureFillCapability, type ControlMeasureGeometry, type ControlMeasureGeometryType, type ControlMeasureId, type ControlMeasureKind, type ControlMeasureMetadata, type ControlMeasureOptionHandle, type ControlMeasureOptionHandleDragEvent, type ControlMeasureOptionHandles, type ControlMeasurePaintCapability, type ControlMeasureRender, type ControlMeasureRenderContext, type ControlMeasureStyle, type CounterattackByFireOptions, type CounterattackOptions, 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_BRIDGEHEAD_LINE_OPTIONS, DEFAULT_BYPASS_OPTIONS, DEFAULT_CANALIZE_OPTIONS, DEFAULT_CLASSIC_ARROW_OPTIONS, DEFAULT_CLEAR_OPTIONS, DEFAULT_CONTAIN_OPTIONS, DEFAULT_COUNTERATTACK_BY_FIRE_OPTIONS, DEFAULT_COUNTERATTACK_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_DISENGAGE_OPTIONS, DEFAULT_DISRUPT_MISSION_TASK_OPTIONS, DEFAULT_DISRUPT_OPTIONS, DEFAULT_ENCIRCLEMENT_OPTIONS, DEFAULT_ENGAGEMENT_AREA_OPTIONS, DEFAULT_ENGINEER_WORK_LINE_OPTIONS, DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, DEFAULT_FIX_MISSION_TASK_OPTIONS, DEFAULT_FIX_OPTIONS, DEFAULT_FLOT_OPTIONS, DEFAULT_FORTIFIED_AREA_OPTIONS, DEFAULT_FORTIFIED_LINE_OPTIONS, DEFAULT_FORWARD_EDGE_OF_BATTLE_AREA_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_GENERIC_SECTOR_OPTIONS, DEFAULT_GENERIC_TEXT_OPTIONS, DEFAULT_GUARD_OPTIONS, DEFAULT_HANDOVER_LINE_OPTIONS, DEFAULT_HOLDING_LINE_OPTIONS, DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, DEFAULT_LABEL_HEIGHT_CSS_PIXELS, DEFAULT_LABEL_SIZE_CLAMP_CSS_PIXELS, DEFAULT_LANDING_ZONE_OPTIONS, DEFAULT_LIGHT_LINE_OPTIONS, DEFAULT_LIMIT_OF_ADVANCE_OPTIONS, DEFAULT_LINE_CAP, DEFAULT_LINE_JOIN, DEFAULT_LINE_OF_DEPARTURE_CONTACT_OPTIONS, DEFAULT_LINE_OF_DEPARTURE_OPTIONS, DEFAULT_MAIN_ATTACK_OPTIONS, DEFAULT_MINEFIELD_OPTIONS, DEFAULT_MOBILE_DEFENSE_OPTIONS, DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, DEFAULT_PENETRATE_OPTIONS, DEFAULT_PHASE_LINE_OPTIONS, DEFAULT_PICKUP_ZONE_OPTIONS, DEFAULT_PORTRAYAL, DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, DEFAULT_PROBABLE_LINE_OF_DEPLOYMENT_OPTIONS, DEFAULT_RADAR_SEARCH_DOCTRINE_OPTIONS, DEFAULT_REARWARD_PASSAGE_OF_LINES_OPTIONS, DEFAULT_RELEASE_LINE_OPTIONS, DEFAULT_RETAIN_OPTIONS, DEFAULT_RETIRE_OPTIONS, DEFAULT_SCREEN_OPTIONS, DEFAULT_SECONDARY_DIRECTION_OF_FIRE_OPTIONS, DEFAULT_SEIZE_OPTIONS, DEFAULT_STROKE_DASH_CSS_PIXELS, DEFAULT_STROKE_WIDTH_CSS_PIXELS, DEFAULT_STRONG_POINT_OPTIONS, DEFAULT_SUPPORTING_ATTACK_OPTIONS, DEFAULT_SUPPORT_BY_FIRE_OPTIONS, DEFAULT_TACTICAL_ARROW_OPTIONS, DEFAULT_TURNING_MOVEMENT_OPTIONS, DEFAULT_TURN_OPTIONS, DEFAULT_WITHDRAW_OPTIONS, DEFAULT_WITHDRAW_UNDER_PRESSURE_OPTIONS, type DelayOptions, type DirectionOfAttackAviationOptions, type DirectionOfMainAttackOptions, type DirectionOfSupportingAttackOptions, type DisengageOptions, type DisruptMissionTaskOptions, type DisruptOptions, EPSILON, type EncirclementOptions, type EngagementAreaOptions, type EngineerWorkLineOptions, FILL_PATTERN_DEFINITIONS, type FLOTOptions, type FeaturePartProps, type FillPattern, type FillPatternCommand, type FillPatternDefinition, type FinalProtectiveFireOptions, type FixMissionTaskOptions, type FixOptions, type FortifiedAreaOptions, type FortifiedLineOptions, type ForwardEdgeOfBattleAreaOptions, type FrontalAttackOptions, type GeneratedLabelKey, type GenericC2LineOptions, type GenericCircleOptions, type GenericLineOptions, type GenericPolygonOptions, type GenericRectangleOptions, type GenericSectorOptions, type GenericTextOptions, type GuardOptions, type HandoverLineOptions, type HoldingLineOptions, type JointTacticalActionAreaOptions, type LabelPlacementOverride, type LabelSizeOptions, type LandingZoneOptions, type LightLineOptions, type LimitOfAdvanceOptions, type LineOfDepartureContactOptions, type LineOfDepartureOptions, type LogicalTextStyle, type MainAttackOptions, type MeasureTextRequest, type MeasuredText, type MidpointPerpendicularDrawRuleOptions, type MineType, type MinefieldOptions, type MobileDefenseOptions, NON_SOLID_FILL_PATTERNS, type ObstacleBypassDifficultOptions, type ObstacleBypassEasyOptions, type ObstacleBypassImpossibleOptions, type OptionsByKind, PARAMETER_PRESENTATION_TIERS, PROBABLE_LINE_OF_DEPLOYMENT_DASH, type ParamDescriptor, type ParameterPresentationTier, type ParameterSemanticRole, type PatternId, type PatternPaint, type PatternPathOperation, type PatternPoint, type PatternStroke, type PenetrateOptions, type PhaseLineOptions, type PickupZoneOptions, type Point2D, type PrincipalDirectionOfFireOptions, type ProbableLineOfDeploymentOptions, RADAR_SEARCH_DOCTRINE_FILL_COLOR, RADAR_SEARCH_DOCTRINE_STROKE_COLOR, type RadarSearchDoctrineOptions, type RearwardPassageOfLinesOptions, type ReleaseLineOptions, type RenderOptions, type RetainOptions, type RetireOptions, SECONDARY_DIRECTION_OF_FIRE_DASH, type ScreenOptions, type SecondaryDirectionOfFireOptions, type SeizeOptions, 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, type WithdrawOptions, type WithdrawUnderPressureOptions, ambushDrawRule, applyBoxTransformOptions, area27DrawRule, attackByFireDrawRule, axis1DrawRule, blockDrawRule, calculateMetrics, canonicalTextAmplifierKey, centerRadiusDrawRule, cloneControlMeasure, computeDefaultMidpointPerpendicularPoint, computeInitialWidthPoint, containDrawRule, controlMeasureIdFromFeature, createBaselineFrame, createMidpointPerpendicularDrawRule, disruptDrawRule, dragControlMeasureOptionHandle, dynamicPointDrawRule, foldsBoxTransformOptions, freezeOrientationOptions, getControlMeasureMetadata, getControlMeasureMetadataByValue, getControlMeasureOptionHandles, getDefaultOptions, getFillPatternDefinition, getMetersPerPixel, getMidpointPerpendicularSignedDistance, haversineDistance, isKind, line1DrawRule, line23DrawRule, line24DrawRule, line26DrawRule, line27DrawRule, listControlMeasureMetadata, normalizeTextAmplifiers, parameterPresentationTierRank, penetrateDrawRule, point12DrawRule, pointOnMidpointPerpendicularAxis, project, rectangleDrawRule, renderControlMeasure, resolveAmplifierPlacement, resolveParameterPresentationTier, resolveParameterSemanticRole, resolveStyleHints, roundToFixed, sectorDrawRule, snapToMidpointPerpendicular, sphericalBearing, staticPointDrawRule, supportByFireDrawRule, toSimpleStyle, turnDrawRule, unproject };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as DEFAULT_DISRUPT_OPTIONS, $t as DEFAULT_STROKE_DASH_CSS_PIXELS, A as DEFAULT_RETIRE_OPTIONS, An as createBaselineFrame, At as DEFAULT_CONTAIN_OPTIONS, B as DEFAULT_LIMIT_OF_ADVANCE_OPTIONS, Bt as DEFAULT_AREA_DEFENSE_OPTIONS, C as DEFAULT_MAIN_ATTACK_OPTIONS, Cn as containDrawRule, Ct as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, D as DEFAULT_WITHDRAW_OPTIONS, Dn as getMidpointPerpendicularSignedDistance, Dt as DEFAULT_BOUNDARY_OPTIONS, E as DEFAULT_WITHDRAW_UNDER_PRESSURE_OPTIONS, En as createMidpointPerpendicularDrawRule, Et as DEFAULT_LIGHT_LINE_OPTIONS, F as DEFAULT_FORTIFIED_LINE_OPTIONS, Fn as sphericalBearing, Ft as DEFAULT_ANTITANK_DITCH_OPTIONS, G as DEFAULT_HOLDING_LINE_OPTIONS, Gt as canonicalTextAmplifierKey, H as DEFAULT_HANDOVER_LINE_OPTIONS, Ht as DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS, I as DEFAULT_PROBABLE_LINE_OF_DEPLOYMENT_OPTIONS, In as unproject, It as DEFAULT_ASSEMBLY_AREA_OPTIONS, J as DEFAULT_FLOT_OPTIONS, Jt as DEFAULT_LABEL_HEIGHT_CSS_PIXELS, K as DEFAULT_BRIDGEHEAD_LINE_OPTIONS, Kt as normalizeTextAmplifiers, L as PROBABLE_LINE_OF_DEPLOYMENT_DASH, Ln as EPSILON, Lt as DEFAULT_AREA_OF_OPERATIONS_OPTIONS, M as DEFAULT_PENETRATE_OPTIONS, Mn as computeInitialWidthPoint, Mt as DEFAULT_ATTACK_HELICOPTER_OPTIONS, N as DEFAULT_FRONTAL_ATTACK_OPTIONS, Nn as haversineDistance, Nt as DEFAULT_ATTACK_BY_FIRE_OPTIONS, O as DEFAULT_SEIZE_OPTIONS, On as pointOnMidpointPerpendicularAxis, Ot as DEFAULT_BLOCK_ARROW_OPTIONS, P as DEFAULT_FORTIFIED_AREA_OPTIONS, Pn as project, Pt as DEFAULT_ANTITANK_WALL_OPTIONS, Q as DEFAULT_ENCIRCLEMENT_OPTIONS, Qt as DEFAULT_PORTRAYAL, R as DEFAULT_LINE_OF_DEPARTURE_CONTACT_OPTIONS, Rn as getMetersPerPixel, Rt as DEFAULT_MOBILE_DEFENSE_OPTIONS, S as DEFAULT_MINEFIELD_OPTIONS, Sn as centerRadiusDrawRule, St as DEFAULT_BREACH_OPTIONS, T as DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, Tn as computeDefaultMidpointPerpendicularPoint, Tt as DEFAULT_ENGINEER_WORK_LINE_OPTIONS, U as DEFAULT_FORWARD_EDGE_OF_BATTLE_AREA_OPTIONS, Ut as DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS, V as DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, Vt as DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS, W as DEFAULT_RELEASE_LINE_OPTIONS, Wt as TEXT_AMPLIFIER_FIELDS, X as DEFAULT_FIX_OPTIONS, Xt as DEFAULT_LINE_CAP, Y as DEFAULT_FIX_MISSION_TASK_OPTIONS, Yt as DEFAULT_LABEL_SIZE_CLAMP_CSS_PIXELS, Z as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, Zt as DEFAULT_LINE_JOIN, _ as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, _n as staticPointDrawRule, _t as DEFAULT_GENERIC_LINE_OPTIONS, a as DEFINITIONS, an as axis1DrawRule, at as DEFAULT_TACTICAL_ARROW_OPTIONS, b as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, bn as disruptDrawRule, bt as DEFAULT_CANALIZE_OPTIONS, c as getDefaultOptions, cn as line26DrawRule, ct as DEFAULT_SUPPORTING_ATTACK_OPTIONS, d as DEFAULT_TURN_OPTIONS, dn as turnDrawRule, dt as RADAR_SEARCH_DOCTRINE_FILL_COLOR, en as DEFAULT_STROKE_WIDTH_CSS_PIXELS, et as DEFAULT_GUARD_OPTIONS, f as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, fn as line1DrawRule, ft as RADAR_SEARCH_DOCTRINE_STROKE_COLOR, g as SECONDARY_DIRECTION_OF_FIRE_DASH, gn as sectorDrawRule, gt as DEFAULT_GENERIC_POLYGON_OPTIONS, h as DEFAULT_SECONDARY_DIRECTION_OF_FIRE_OPTIONS, hn as dynamicPointDrawRule, ht as DEFAULT_GENERIC_RECTANGLE_OPTIONS, i as CONTROL_MEASURE_METADATA, in as rectangleDrawRule, it as DEFAULT_COVER_OPTIONS, j as DEFAULT_REARWARD_PASSAGE_OF_LINES_OPTIONS, jn as calculateMetrics, jt as DEFAULT_BATTLE_POSITION_OPTIONS, k as DEFAULT_SCREEN_OPTIONS, kn as snapToMidpointPerpendicular, kt as DEFAULT_BLOCK_OPTIONS, l as listControlMeasureMetadata, ln as line24DrawRule, lt as DEFAULT_CLEAR_OPTIONS, m as DEFAULT_STRONG_POINT_OPTIONS, mn as attackByFireDrawRule, mt as DEFAULT_GENERIC_SECTOR_OPTIONS, n as resolveStyleHints, nn as DEFAULT_AMBUSH_OPTIONS, nt as DEFAULT_DISENGAGE_OPTIONS, o as getControlMeasureMetadata, on as supportByFireDrawRule, ot as DEFAULT_COUNTERATTACK_BY_FIRE_OPTIONS, p as DEFAULT_RETAIN_OPTIONS, pn as ambushDrawRule, pt as DEFAULT_GENERIC_TEXT_OPTIONS, q as DEFAULT_PHASE_LINE_OPTIONS, qt as resolveAmplifierPlacement, r as CONTROL_MEASURE_IDS, rn as DEFAULT_AIRBORNE_ATTACK_OPTIONS, rt as DEFAULT_DELAY_OPTIONS, s as getControlMeasureMetadataByValue, sn as line27DrawRule, st as DEFAULT_COUNTERATTACK_OPTIONS, t as renderControlMeasure, tt as DEFAULT_DISRUPT_MISSION_TASK_OPTIONS, u as DEFAULT_TURNING_MOVEMENT_OPTIONS, un as line23DrawRule, ut as DEFAULT_RADAR_SEARCH_DOCTRINE_OPTIONS, v as DEFAULT_PICKUP_ZONE_OPTIONS, vn as point12DrawRule, vt as DEFAULT_GENERIC_CIRCLE_OPTIONS, w as DEFAULT_LANDING_ZONE_OPTIONS, wn as area27DrawRule, wt as DEFAULT_GENERIC_C2_LINE_OPTIONS, x as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, xn as blockDrawRule, xt as DEFAULT_BYPASS_OPTIONS, y as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, yn as penetrateDrawRule, yt as DEFAULT_CLASSIC_ARROW_OPTIONS, z as DEFAULT_LINE_OF_DEPARTURE_OPTIONS, zn as roundToFixed, zt as DEFAULT_ENGAGEMENT_AREA_OPTIONS } from "./renderControlMeasure-CclYDSlM.mjs";
1
+ import { $ as DEFAULT_DISRUPT_OPTIONS, $t as DEFAULT_STROKE_DASH_CSS_PIXELS, A as DEFAULT_RETIRE_OPTIONS, An as createBaselineFrame, At as DEFAULT_CONTAIN_OPTIONS, B as DEFAULT_LIMIT_OF_ADVANCE_OPTIONS, Bt as DEFAULT_AREA_DEFENSE_OPTIONS, C as DEFAULT_MAIN_ATTACK_OPTIONS, Cn as containDrawRule, Ct as DEFAULT_BLOCK_MISSION_TASK_OPTIONS, D as DEFAULT_WITHDRAW_OPTIONS, Dn as getMidpointPerpendicularSignedDistance, Dt as DEFAULT_BOUNDARY_OPTIONS, E as DEFAULT_WITHDRAW_UNDER_PRESSURE_OPTIONS, En as createMidpointPerpendicularDrawRule, Et as DEFAULT_LIGHT_LINE_OPTIONS, F as DEFAULT_FORTIFIED_LINE_OPTIONS, Fn as sphericalBearing, Ft as DEFAULT_ANTITANK_DITCH_OPTIONS, G as DEFAULT_HOLDING_LINE_OPTIONS, Gt as canonicalTextAmplifierKey, H as DEFAULT_HANDOVER_LINE_OPTIONS, Ht as DEFAULT_DIRECTION_OF_MAIN_ATTACK_OPTIONS, I as DEFAULT_PROBABLE_LINE_OF_DEPLOYMENT_OPTIONS, In as unproject, It as DEFAULT_ASSEMBLY_AREA_OPTIONS, J as DEFAULT_FLOT_OPTIONS, Jt as DEFAULT_LABEL_HEIGHT_CSS_PIXELS, K as DEFAULT_BRIDGEHEAD_LINE_OPTIONS, Kt as normalizeTextAmplifiers, L as PROBABLE_LINE_OF_DEPLOYMENT_DASH, Ln as EPSILON, Lt as DEFAULT_AREA_OF_OPERATIONS_OPTIONS, M as DEFAULT_PENETRATE_OPTIONS, Mn as computeInitialWidthPoint, Mt as DEFAULT_ATTACK_HELICOPTER_OPTIONS, N as DEFAULT_FRONTAL_ATTACK_OPTIONS, Nn as haversineDistance, Nt as DEFAULT_ATTACK_BY_FIRE_OPTIONS, O as DEFAULT_SEIZE_OPTIONS, On as pointOnMidpointPerpendicularAxis, Ot as DEFAULT_BLOCK_ARROW_OPTIONS, P as DEFAULT_FORTIFIED_AREA_OPTIONS, Pn as project, Pt as DEFAULT_ANTITANK_WALL_OPTIONS, Q as DEFAULT_ENCIRCLEMENT_OPTIONS, Qt as DEFAULT_PORTRAYAL, R as DEFAULT_LINE_OF_DEPARTURE_CONTACT_OPTIONS, Rn as getMetersPerPixel, Rt as DEFAULT_MOBILE_DEFENSE_OPTIONS, S as DEFAULT_MINEFIELD_OPTIONS, Sn as centerRadiusDrawRule, St as DEFAULT_BREACH_OPTIONS, T as DEFAULT_JOINT_TACTICAL_ACTION_AREA_OPTIONS, Tn as computeDefaultMidpointPerpendicularPoint, Tt as DEFAULT_ENGINEER_WORK_LINE_OPTIONS, U as DEFAULT_FORWARD_EDGE_OF_BATTLE_AREA_OPTIONS, Ut as DEFAULT_DIRECTION_OF_ATTACK_AVIATION_OPTIONS, V as DEFAULT_BATTLE_HANDOVER_LINE_OPTIONS, Vt as DEFAULT_DIRECTION_OF_SUPPORTING_ATTACK_OPTIONS, W as DEFAULT_RELEASE_LINE_OPTIONS, Wt as TEXT_AMPLIFIER_FIELDS, X as DEFAULT_FIX_OPTIONS, Xt as DEFAULT_LINE_CAP, Y as DEFAULT_FIX_MISSION_TASK_OPTIONS, Yt as DEFAULT_LABEL_SIZE_CLAMP_CSS_PIXELS, Z as DEFAULT_FINAL_PROTECTIVE_FIRE_OPTIONS, Zt as DEFAULT_LINE_JOIN, _ as DEFAULT_PRINCIPAL_DIRECTION_OF_FIRE_OPTIONS, _n as staticPointDrawRule, _t as DEFAULT_GENERIC_LINE_OPTIONS, a as DEFINITIONS, an as axis1DrawRule, at as DEFAULT_TACTICAL_ARROW_OPTIONS, b as DEFAULT_OBSTACLE_BYPASS_EASY_OPTIONS, bn as disruptDrawRule, bt as DEFAULT_CANALIZE_OPTIONS, c as getDefaultOptions, cn as line26DrawRule, ct as DEFAULT_SUPPORTING_ATTACK_OPTIONS, d as DEFAULT_TURN_OPTIONS, dn as turnDrawRule, dt as RADAR_SEARCH_DOCTRINE_FILL_COLOR, en as DEFAULT_STROKE_WIDTH_CSS_PIXELS, et as DEFAULT_GUARD_OPTIONS, f as DEFAULT_SUPPORT_BY_FIRE_OPTIONS, fn as line1DrawRule, ft as RADAR_SEARCH_DOCTRINE_STROKE_COLOR, g as SECONDARY_DIRECTION_OF_FIRE_DASH, gn as sectorDrawRule, gt as DEFAULT_GENERIC_POLYGON_OPTIONS, h as DEFAULT_SECONDARY_DIRECTION_OF_FIRE_OPTIONS, hn as dynamicPointDrawRule, ht as DEFAULT_GENERIC_RECTANGLE_OPTIONS, i as CONTROL_MEASURE_METADATA, in as rectangleDrawRule, it as DEFAULT_COVER_OPTIONS, j as DEFAULT_REARWARD_PASSAGE_OF_LINES_OPTIONS, jn as calculateMetrics, jt as DEFAULT_BATTLE_POSITION_OPTIONS, k as DEFAULT_SCREEN_OPTIONS, kn as snapToMidpointPerpendicular, kt as DEFAULT_BLOCK_OPTIONS, l as listControlMeasureMetadata, ln as line24DrawRule, lt as DEFAULT_CLEAR_OPTIONS, m as DEFAULT_STRONG_POINT_OPTIONS, mn as attackByFireDrawRule, mt as DEFAULT_GENERIC_SECTOR_OPTIONS, n as resolveStyleHints, nn as DEFAULT_AMBUSH_OPTIONS, nt as DEFAULT_DISENGAGE_OPTIONS, o as getControlMeasureMetadata, on as supportByFireDrawRule, ot as DEFAULT_COUNTERATTACK_BY_FIRE_OPTIONS, p as DEFAULT_RETAIN_OPTIONS, pn as ambushDrawRule, pt as DEFAULT_GENERIC_TEXT_OPTIONS, q as DEFAULT_PHASE_LINE_OPTIONS, qt as resolveAmplifierPlacement, r as CONTROL_MEASURE_IDS, rn as DEFAULT_AIRBORNE_ATTACK_OPTIONS, rt as DEFAULT_DELAY_OPTIONS, s as getControlMeasureMetadataByValue, sn as line27DrawRule, st as DEFAULT_COUNTERATTACK_OPTIONS, t as renderControlMeasure, tt as DEFAULT_DISRUPT_MISSION_TASK_OPTIONS, u as DEFAULT_TURNING_MOVEMENT_OPTIONS, un as line23DrawRule, ut as DEFAULT_RADAR_SEARCH_DOCTRINE_OPTIONS, v as DEFAULT_PICKUP_ZONE_OPTIONS, vn as point12DrawRule, vt as DEFAULT_GENERIC_CIRCLE_OPTIONS, w as DEFAULT_LANDING_ZONE_OPTIONS, wn as area27DrawRule, wt as DEFAULT_GENERIC_C2_LINE_OPTIONS, x as DEFAULT_OBSTACLE_BYPASS_DIFFICULT_OPTIONS, xn as blockDrawRule, xt as DEFAULT_BYPASS_OPTIONS, y as DEFAULT_OBSTACLE_BYPASS_IMPOSSIBLE_OPTIONS, yn as penetrateDrawRule, yt as DEFAULT_CLASSIC_ARROW_OPTIONS, z as DEFAULT_LINE_OF_DEPARTURE_OPTIONS, zn as roundToFixed, zt as DEFAULT_ENGAGEMENT_AREA_OPTIONS } from "./renderControlMeasure-YkkjLyTx.mjs";
2
2
  import { FILL_PATTERN_DEFINITIONS, NON_SOLID_FILL_PATTERNS, getFillPatternDefinition } from "./patterns.mjs";
3
3
  //#region src/metadata.ts
4
4
  const PARAMETER_PRESENTATION_TIERS = [
@@ -1,4 +1,4 @@
1
- import { et as ControlMeasureId, ga as TextAmplifiers } from "../index-IeI0ELGA.mjs";
1
+ import { et as ControlMeasureId, ga as TextAmplifiers } from "../index-BzMR6vIE.mjs";
2
2
  import { f as FillPattern } from "../patterns-CcQmmOuJ.mjs";
3
3
  import { FeatureCollection, Geometry } from "geojson";
4
4
 
@@ -88,6 +88,17 @@ interface PreviewShape {
88
88
  /** Typography preset, mirroring the label feature's `textStyle`. */
89
89
  textStyle?: "regular" | "italic" | "light" | "caps";
90
90
  }
91
+ /** One centered SVG row derived from a preview shape's explicit line breaks. */
92
+ interface PreviewTextRow {
93
+ text: string;
94
+ x: number | undefined;
95
+ y: number;
96
+ }
97
+ /**
98
+ * Splits a text preview shape into centered SVG rows. Consumers render each
99
+ * row as a `<tspan>` so explicit line breaks survive SVG whitespace collapse.
100
+ */
101
+ declare function previewTextRows(shape: PreviewShape, fontSize: number): PreviewTextRow[];
91
102
  /** Target viewBox the geometry is fit into. */
92
103
  interface ProjectDimensions {
93
104
  width: number;
@@ -111,6 +122,8 @@ declare function projectRenderToShapes(fc: FeatureCollection<Geometry, unknown>,
111
122
  * consumer that paints the backdrop rect so the box width stays consistent.
112
123
  */
113
124
  declare function previewLabelBackgroundWidth(text: string | undefined, fontSize: number): number;
125
+ /** On-screen height of a text label's preview background, including padding. */
126
+ declare function previewLabelBackgroundHeight(text: string | undefined, fontSize: number): number;
114
127
  /**
115
128
  * Grows a viewBox to include every `text` shape's estimated on-screen box —
116
129
  * {@link projectRenderToShapes} fits geometry coordinates only, so an
@@ -160,4 +173,4 @@ declare function viewBoxString(shapes: PreviewShape[], dims: {
160
173
  */
161
174
  declare function svgTextTransform(s: PreviewShape): string | undefined;
162
175
  //#endregion
163
- export { PREVIEW_FILL_PATTERNS, PREVIEW_PATTERN_DOT_RADIUS, PREVIEW_PATTERN_TILE, PreviewFillPattern, PreviewShape, ProjectDimensions, previewLabelBackgroundWidth, projectRenderToShapes, renderRepresentative, svgTextTransform, viewBoxString, viewBoxWithLabels };
176
+ export { PREVIEW_FILL_PATTERNS, PREVIEW_PATTERN_DOT_RADIUS, PREVIEW_PATTERN_TILE, PreviewFillPattern, PreviewShape, PreviewTextRow, ProjectDimensions, previewLabelBackgroundHeight, previewLabelBackgroundWidth, previewTextRows, projectRenderToShapes, renderRepresentative, svgTextTransform, viewBoxString, viewBoxWithLabels };
@@ -1,4 +1,4 @@
1
- import { a as DEFINITIONS, t as renderControlMeasure } from "../renderControlMeasure-CclYDSlM.mjs";
1
+ import { a as DEFINITIONS, t as renderControlMeasure } from "../renderControlMeasure-YkkjLyTx.mjs";
2
2
  import { FILL_PATTERN_DEFINITIONS, NON_SOLID_FILL_PATTERNS } from "../patterns.mjs";
3
3
  //#region src/preview/index.ts
4
4
  /** Side length (SVG units) of the repeating non-mine tile in {@link PREVIEW_FILL_PATTERNS}. */
@@ -139,6 +139,20 @@ function renderRepresentative(id, overrides) {
139
139
  };
140
140
  }
141
141
  }
142
+ /** Line pitch used by preview SVG consumers, relative to the font size. */
143
+ const PREVIEW_TEXT_LINE_HEIGHT_RATIO = 1.2;
144
+ /**
145
+ * Splits a text preview shape into centered SVG rows. Consumers render each
146
+ * row as a `<tspan>` so explicit line breaks survive SVG whitespace collapse.
147
+ */
148
+ function previewTextRows(shape, fontSize) {
149
+ const lines = (shape.text ?? "").split("\n");
150
+ return lines.map((text, index) => ({
151
+ text,
152
+ x: shape.cx,
153
+ y: (shape.cy ?? 0) + (index - (lines.length - 1) / 2) * fontSize * PREVIEW_TEXT_LINE_HEIGHT_RATIO
154
+ }));
155
+ }
142
156
  /**
143
157
  * Fits a rendered `FeatureCollection` into a `width`×`height` viewBox (inset by
144
158
  * `pad`) and emits preview-ready {@link PreviewShape}s. North is up (y is
@@ -194,13 +208,31 @@ const METERS_PER_DEGREE = 111320;
194
208
  * not to lay out real text. */
195
209
  const CHAR_WIDTH_RATIO = .62;
196
210
  /**
211
+ * Estimated on-screen box of a (possibly multiline) label at `fontSize`: the
212
+ * longest line's glyph run wide, and one line plus {@link
213
+ * PREVIEW_TEXT_LINE_HEIGHT_RATIO} per extra line tall. The single place that
214
+ * knows how `"\n"`-separated preview text measures, so every consumer — the
215
+ * backdrop box, the viewBox extents, the text-height fit — stays in step.
216
+ */
217
+ function previewTextBlockDimensions(text, fontSize, charWidthRatio = CHAR_WIDTH_RATIO) {
218
+ const lines = (text ?? "").split("\n");
219
+ return {
220
+ width: Math.max(...lines.map((line) => line.length)) * fontSize * charWidthRatio,
221
+ height: fontSize * (1 + (lines.length - 1) * PREVIEW_TEXT_LINE_HEIGHT_RATIO)
222
+ };
223
+ }
224
+ /**
197
225
  * On-screen width (SVG units) of a `textBackground` label's readability box at
198
226
  * `fontSize`: the glyph run (via {@link CHAR_WIDTH_RATIO}) or the font size,
199
227
  * whichever is wider, plus a small horizontal pad. Shared by every preview
200
228
  * consumer that paints the backdrop rect so the box width stays consistent.
201
229
  */
202
230
  function previewLabelBackgroundWidth(text, fontSize) {
203
- return Math.max(fontSize, (text?.length ?? 0) * fontSize * CHAR_WIDTH_RATIO) + 6;
231
+ return Math.max(fontSize, previewTextBlockDimensions(text, fontSize).width) + 6;
232
+ }
233
+ /** On-screen height of a text label's preview background, including padding. */
234
+ function previewLabelBackgroundHeight(text, fontSize) {
235
+ return previewTextBlockDimensions(text, fontSize).height + 4;
204
236
  }
205
237
  /**
206
238
  * Glyph-width ratio for {@link viewBoxWithLabels}' extent boxes. Deliberately
@@ -251,8 +283,7 @@ function viewBoxWithLabels(shapes, dims, fontSize) {
251
283
  for (const s of shapes) {
252
284
  if (s.type !== "text" || s.cx === void 0 || s.cy === void 0) continue;
253
285
  const font = fontSize(s);
254
- const w = (s.text?.length ?? 0) * EXTENT_CHAR_WIDTH_RATIO * font;
255
- const h = font;
286
+ const { width: w, height: h } = previewTextBlockDimensions(s.text, font, EXTENT_CHAR_WIDTH_RATIO);
256
287
  const left = s.textAnchor === "start" ? s.cx : s.textAnchor === "end" ? s.cx - w : s.cx - w / 2;
257
288
  const right = left + w;
258
289
  const top = s.cy - h / 2;
@@ -317,7 +348,8 @@ function resolveTextHeightPx(labelProps, text, limits) {
317
348
  const sizeMeters = labelProps.textSizeMeters;
318
349
  if (typeof sizeMeters !== "number") return void 0;
319
350
  const raw = sizeMeters * limits.scale / METERS_PER_DEGREE;
320
- const widthLimit = text.length > 0 ? limits.maxWidthPx / (text.length * CHAR_WIDTH_RATIO) : Infinity;
351
+ const runWidth = previewTextBlockDimensions(text, 1).width;
352
+ const widthLimit = runWidth > 0 ? limits.maxWidthPx / runWidth : Infinity;
321
353
  return Math.min(raw, limits.maxHeightPx, widthLimit);
322
354
  }
323
355
  function ringArea(ring) {
@@ -451,4 +483,4 @@ function collectShapes(g, tx, out, bboxArea, textLimits, props) {
451
483
  }
452
484
  }
453
485
  //#endregion
454
- export { PREVIEW_FILL_PATTERNS, PREVIEW_PATTERN_DOT_RADIUS, PREVIEW_PATTERN_TILE, previewLabelBackgroundWidth, projectRenderToShapes, renderRepresentative, svgTextTransform, viewBoxString, viewBoxWithLabels };
486
+ export { PREVIEW_FILL_PATTERNS, PREVIEW_PATTERN_DOT_RADIUS, PREVIEW_PATTERN_TILE, previewLabelBackgroundHeight, previewLabelBackgroundWidth, previewTextRows, projectRenderToShapes, renderRepresentative, svgTextTransform, viewBoxString, viewBoxWithLabels };
@@ -280,7 +280,7 @@ const SHAFT_WIDTH_OPTION_HANDLE_ID = "shaft-width";
280
280
  /**
281
281
  * Creates the definition-owned rear-/shaft-width handle pair shared by every
282
282
  * variable-width arrow body. Callers supply only how their own geometry maps
283
- * onto {@link WidthHandleGeometry}; placement (the two ends of the left edge)
283
+ * onto {@link WidthHandleGeometry}; placement (the two ends of the right edge)
284
284
  * and the drag math (perpendicular distance from the dragged point to the
285
285
  * matching centerline segment, over the reference half-width) live here once.
286
286
  */
@@ -288,15 +288,15 @@ function createWidthOptionHandles(config) {
288
288
  return {
289
289
  get(controlPoints, options) {
290
290
  const geometry = config.geometry(controlPoints, options);
291
- const rearLeft = geometry?.leftEdge[0];
292
- const neckLeft = geometry?.leftEdge.at(-1);
293
- if (!rearLeft || !neckLeft) return [];
291
+ const rearRight = geometry?.rightEdge[0];
292
+ const neckRight = geometry?.rightEdge.at(-1);
293
+ if (!rearRight || !neckRight) return [];
294
294
  return [{
295
295
  id: REAR_WIDTH_OPTION_HANDLE_ID,
296
- position: unproject(rearLeft[0], rearLeft[1])
296
+ position: unproject(rearRight[0], rearRight[1])
297
297
  }, {
298
298
  id: SHAFT_WIDTH_OPTION_HANDLE_ID,
299
- position: unproject(neckLeft[0], neckLeft[1])
299
+ position: unproject(neckRight[0], neckRight[1])
300
300
  }];
301
301
  },
302
302
  drag({ controlPoints, options, handleId, position }) {
@@ -328,7 +328,7 @@ function createVariableWidthAttackOptionHandles(resolveCoordinates = (points) =>
328
328
  if (!geometry || !outerLeft) return null;
329
329
  return {
330
330
  spine: geometry.shaftCenterline,
331
- leftEdge: geometry.shaftLeft,
331
+ rightEdge: geometry.shaftRight,
332
332
  referenceHalfWidth: vecMag(vecSub(outerLeft, geometry.ptBase))
333
333
  };
334
334
  },
@@ -1697,6 +1697,16 @@ const ECHELON_PARAM_OPTIONS = [{
1697
1697
  label: spec.label,
1698
1698
  value
1699
1699
  }))];
1700
+ /**
1701
+ * Effective echelon glyph height in meters. Screen-anchored when a pixel size
1702
+ * is supplied with a live resolution; ground-anchored (meters) otherwise.
1703
+ * Clamped strictly positive.
1704
+ */
1705
+ function resolveEchelonHeight(echelonSize, echelonSizePixels, metersPerPixel) {
1706
+ let h = echelonSize;
1707
+ if (echelonSizePixels !== void 0 && metersPerPixel !== void 0 && metersPerPixel > 0) h = echelonSizePixels * metersPerPixel;
1708
+ return Math.max(EPSILON, h);
1709
+ }
1700
1710
  function resolveEchelon(echelon) {
1701
1711
  const key = echelon.trim().toLowerCase();
1702
1712
  if (key.length === 0) return void 0;
@@ -1952,9 +1962,19 @@ const AREA_LABEL_PADDING_PARAM = {
1952
1962
  max: 2,
1953
1963
  step: .05
1954
1964
  };
1965
+ const MULTILINE_AREA_LABEL_PARAM = {
1966
+ key: "multilineLabel",
1967
+ label: "Multiline label",
1968
+ description: "Place the doctrinal label above Field T on separate centered lines",
1969
+ type: "boolean"
1970
+ };
1955
1971
  const LABELED_AREA_PARAMS = [...AREA_SMOOTH_PARAMS, AREA_LABEL_PADDING_PARAM];
1956
- const ECHELON_AREA_PARAMS = [
1972
+ const PREFIXED_LABELED_AREA_PARAMS = [
1957
1973
  ...AREA_SMOOTH_PARAMS,
1974
+ MULTILINE_AREA_LABEL_PARAM,
1975
+ AREA_LABEL_PADDING_PARAM
1976
+ ];
1977
+ const ECHELON_GLYPH_PARAMS = [
1958
1978
  {
1959
1979
  key: "echelon",
1960
1980
  label: "Echelon",
@@ -2003,7 +2023,17 @@ const ECHELON_AREA_PARAMS = [
2003
2023
  min: -.5,
2004
2024
  max: .5,
2005
2025
  step: .01
2006
- },
2026
+ }
2027
+ ];
2028
+ const ECHELON_AREA_PARAMS = [
2029
+ ...AREA_SMOOTH_PARAMS,
2030
+ ...ECHELON_GLYPH_PARAMS,
2031
+ AREA_LABEL_PADDING_PARAM
2032
+ ];
2033
+ const PREFIXED_ECHELON_AREA_PARAMS = [
2034
+ ...AREA_SMOOTH_PARAMS,
2035
+ MULTILINE_AREA_LABEL_PARAM,
2036
+ ...ECHELON_GLYPH_PARAMS,
2007
2037
  AREA_LABEL_PADDING_PARAM
2008
2038
  ];
2009
2039
  const AREA_DESIGNATION_AMPLIFIER = {
@@ -2657,6 +2687,36 @@ function labelRotationAlong(dir) {
2657
2687
  const rendered = -Math.atan2(dir[1], dir[0]);
2658
2688
  return normalizeRadians(Math.PI - keepTextLeftToRight(rendered));
2659
2689
  }
2690
+ const BOUNDARY_UNIT_LABEL_FIELDS = {
2691
+ unit1: {
2692
+ designator: "T",
2693
+ country: "AS"
2694
+ },
2695
+ unit2: {
2696
+ designator: "T1",
2697
+ country: "AS1"
2698
+ }
2699
+ };
2700
+ /** Resolves two echelon-unit rows from a caller-selected set of amplifiers. */
2701
+ function unitLabelsFromAmplifiers(amplifiers, fields = BOUNDARY_UNIT_LABEL_FIELDS) {
2702
+ return [{
2703
+ side: 1,
2704
+ designator: amplifiers[fields.unit1.designator] ?? "",
2705
+ country: amplifiers[fields.unit1.country] ?? ""
2706
+ }, {
2707
+ side: -1,
2708
+ designator: amplifiers[fields.unit2.designator] ?? "",
2709
+ country: amplifiers[fields.unit2.country] ?? ""
2710
+ }];
2711
+ }
2712
+ /** Text size shared by an echelon glyph and its associated unit labels. */
2713
+ function echelonUnitLabelSize(echelonHeight, echelonSizePixels, metersPerPixel) {
2714
+ const screenAnchored = echelonSizePixels !== void 0 && metersPerPixel !== void 0 && metersPerPixel > 0;
2715
+ return {
2716
+ properties: screenAnchored ? { textSizePixels: echelonSizePixels } : { textSizeMeters: echelonHeight },
2717
+ screenAnchored
2718
+ };
2719
+ }
2660
2720
  /**
2661
2721
  * Emits a single combined `T (AS)` label per unit side (APP-6/MIL-STD-2525):
2662
2722
  * designator and country code share one text row rather than stacking.
@@ -2673,6 +2733,37 @@ function pushUnitLabels(out, frame, units) {
2673
2733
  }
2674
2734
  }
2675
2735
  /**
2736
+ * Emits Boundary-style unit labels around echelon groups. Along-line groups
2737
+ * straddle the line; standard-orientation groups on north/south segments form
2738
+ * one row crossing it, anchored outward from the glyph.
2739
+ */
2740
+ function pushEchelonUnitLabels(out, groups, units, echelonHeight, labelPadding, labelSize) {
2741
+ for (const { center, along, perp, rotateGroup, readingAxis, glyphWidth } of groups) {
2742
+ if (rotateGroup) {
2743
+ const sign = vecDot(perp, readingAxis) >= 0 ? 1 : -1;
2744
+ const clearance = glyphWidth / 2 + Math.max(0, labelPadding) * echelonHeight;
2745
+ pushUnitLabels(out, {
2746
+ center,
2747
+ perp: vecScale(readingAxis, sign),
2748
+ offset: clearance,
2749
+ rotation: labelRotationAlong(readingAxis),
2750
+ labelSize
2751
+ }, units.map((unit) => ({
2752
+ ...unit,
2753
+ textAnchor: unit.side === sign ? "start" : "end"
2754
+ })));
2755
+ continue;
2756
+ }
2757
+ pushUnitLabels(out, {
2758
+ center,
2759
+ perp,
2760
+ offset: (.45 + Math.max(0, labelPadding)) * echelonHeight,
2761
+ rotation: labelRotationAlong(along),
2762
+ labelSize
2763
+ }, units);
2764
+ }
2765
+ }
2766
+ /**
2676
2767
  * Walks `verts` (projected meters) into non-degenerate {@link LineSegment}s,
2677
2768
  * skipping coincident vertices (ADR-0014, silent) the same way Boundary's
2678
2769
  * gap-carving does. Empty or fully-degenerate input yields `totalLength: 0`
@@ -2705,6 +2796,15 @@ function clampLinePosition(value, fallback) {
2705
2796
  return Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : fallback;
2706
2797
  }
2707
2798
  /**
2799
+ * Resolves a label/group repetition count to a positive whole number. Takes
2800
+ * `unknown` because the params panel's `visibleWhen` callbacks receive loosely
2801
+ * typed options; non-finite input falls back to a single group.
2802
+ */
2803
+ function resolveLabelRepetitions(value) {
2804
+ const numeric = Number(value ?? 1);
2805
+ return Number.isFinite(numeric) ? Math.max(1, Math.round(numeric)) : 1;
2806
+ }
2807
+ /**
2708
2808
  * Resolves the point at `fraction` (clamped to `[0, 1]`) of `totalLength`
2709
2809
  * along `segments`, walking cumulative arc length exactly like Boundary's
2710
2810
  * label-group placement: the segment containing the target distance absorbs
@@ -3886,16 +3986,6 @@ function pointOnRing(segs, target) {
3886
3986
  seg
3887
3987
  };
3888
3988
  }
3889
- /**
3890
- * Effective echelon glyph height in meters. Screen-anchored when a pixel size
3891
- * is supplied with a live resolution; ground-anchored (meters) otherwise.
3892
- * Clamped strictly positive.
3893
- */
3894
- function resolveEchelonHeight(echelonSize, echelonSizePixels, metersPerPixel) {
3895
- let h = echelonSize;
3896
- if (echelonSizePixels !== void 0 && metersPerPixel !== void 0 && metersPerPixel > 0) h = echelonSizePixels * metersPerPixel;
3897
- return Math.max(EPSILON, h);
3898
- }
3899
3989
  /** Wraps `x` into `[0, 1)`, treating `x` as a fraction (matches the arc-length wrap below). */
3900
3990
  function wrap01(x) {
3901
3991
  return (x % 1 + 1) % 1;
@@ -4006,8 +4096,10 @@ function composeAreaName(prefix, designation, separator = " ") {
4006
4096
  * which differ only in `prefix` (and JTAA's empty `separator`).
4007
4097
  */
4008
4098
  function composeAreaLabelTexts(textAmplifiers, prefix = "", separator = " ") {
4099
+ const designation = textAmplifiers.T?.trim() ?? "";
4009
4100
  return {
4010
- name: composeAreaName(prefix, textAmplifiers.T, separator),
4101
+ name: composeAreaName(prefix, designation, separator),
4102
+ multilineName: prefix && designation ? `${prefix}\n${designation}` : void 0,
4011
4103
  additionalInformation: textAmplifiers.H,
4012
4104
  dtgStart: textAmplifiers.W,
4013
4105
  dtgEnd: textAmplifiers.W1,
@@ -4243,19 +4335,41 @@ function pushAreaLabels(out, ringVerts, texts, options = {}, amplifierPlacements
4243
4335
  const padding = Math.max(0, options.labelPadding ?? 0);
4244
4336
  const maskRingVerts = maskBoundary?.ringVerts ?? ringVerts;
4245
4337
  const [cx, cy] = ringLabelAnchor(ringVerts);
4338
+ const multilineName = options.multilineLabel ? texts.multilineName : void 0;
4246
4339
  const rows = [
4247
- [texts.name, "T"],
4248
- [texts.additionalInformation, "H"],
4249
- [texts.dtgStart, "W"],
4250
- [texts.dtgEnd, "W1"]
4251
- ].flatMap(([text, field]) => text ? [{
4340
+ [
4341
+ multilineName ?? texts.name,
4342
+ "T",
4343
+ multilineName ? multilineName.split("\n").length : 1
4344
+ ],
4345
+ [
4346
+ texts.additionalInformation,
4347
+ "H",
4348
+ 1
4349
+ ],
4350
+ [
4351
+ texts.dtgStart,
4352
+ "W",
4353
+ 1
4354
+ ],
4355
+ [
4356
+ texts.dtgEnd,
4357
+ "W1",
4358
+ 1
4359
+ ]
4360
+ ].flatMap(([text, field, lineCount]) => text ? [{
4252
4361
  text,
4253
- field
4362
+ field,
4363
+ lineCount
4254
4364
  }] : []);
4255
4365
  if (rows.length > 0) {
4256
4366
  const pitch = resolveLabelOffsetMeters(options, ROW_PITCH_RATIO + padding);
4257
- rows.forEach(({ text, field }, i) => {
4258
- pushLabel(out, [cx, cy + ((rows.length - 1) / 2 - i) * pitch], text, HORIZONTAL_LABEL_ROTATION, sizeProps, void 0, field);
4367
+ const totalLineCount = rows.reduce((sum, row) => sum + row.lineCount, 0);
4368
+ let precedingLineCount = 0;
4369
+ rows.forEach(({ text, field, lineCount }) => {
4370
+ const rowCenter = precedingLineCount + (lineCount - 1) / 2;
4371
+ pushLabel(out, [cx, cy + ((totalLineCount - 1) / 2 - rowCenter) * pitch], text, HORIZONTAL_LABEL_ROTATION, sizeProps, void 0, field);
4372
+ precedingLineCount += lineCount;
4259
4373
  });
4260
4374
  }
4261
4375
  if (!texts.hostile) return [];
@@ -4661,7 +4775,7 @@ const ENGAGEMENT_AREA_METADATA = {
4661
4775
  },
4662
4776
  drawRule: "Area1",
4663
4777
  capturesLabelSize: true,
4664
- params: LABELED_AREA_PARAMS,
4778
+ params: PREFIXED_LABELED_AREA_PARAMS,
4665
4779
  textAmplifiers: AREA_TEXT_AMPLIFIERS_DESIGNATION_HOSTILE
4666
4780
  };
4667
4781
  /**
@@ -4928,7 +5042,7 @@ const AREA_OF_OPERATIONS_METADATA = {
4928
5042
  },
4929
5043
  drawRule: "Area1",
4930
5044
  capturesLabelSize: true,
4931
- params: LABELED_AREA_PARAMS,
5045
+ params: PREFIXED_LABELED_AREA_PARAMS,
4932
5046
  textAmplifiers: AREA_TEXT_AMPLIFIERS
4933
5047
  };
4934
5048
  /**
@@ -4952,7 +5066,10 @@ const AREA_OF_OPERATIONS = defineControlMeasure({
4952
5066
  [-1, .5]
4953
5067
  ],
4954
5068
  textAmplifiers: { T: "GREEN" },
4955
- options: { labelSize: 96 }
5069
+ options: {
5070
+ labelSize: 96,
5071
+ multilineLabel: true
5072
+ }
4956
5073
  }
4957
5074
  });
4958
5075
  //#endregion
@@ -4987,7 +5104,7 @@ const NAMED_AREA_OF_INTEREST_METADATA = {
4987
5104
  },
4988
5105
  drawRule: "Area1",
4989
5106
  capturesLabelSize: true,
4990
- params: LABELED_AREA_PARAMS,
5107
+ params: PREFIXED_LABELED_AREA_PARAMS,
4991
5108
  textAmplifiers: AREA_TEXT_AMPLIFIERS_DESIGNATION_HOSTILE
4992
5109
  };
4993
5110
  /**
@@ -5046,7 +5163,7 @@ const TARGET_AREA_OF_INTEREST_METADATA = {
5046
5163
  },
5047
5164
  drawRule: "Area1",
5048
5165
  capturesLabelSize: true,
5049
- params: LABELED_AREA_PARAMS,
5166
+ params: PREFIXED_LABELED_AREA_PARAMS,
5050
5167
  textAmplifiers: AREA_TEXT_AMPLIFIERS_DESIGNATION_HOSTILE
5051
5168
  };
5052
5169
  /**
@@ -5298,7 +5415,7 @@ const BASE_CAMP_METADATA = {
5298
5415
  },
5299
5416
  drawRule: "Area1",
5300
5417
  capturesLabelSize: true,
5301
- params: ECHELON_AREA_PARAMS,
5418
+ params: PREFIXED_ECHELON_AREA_PARAMS,
5302
5419
  textAmplifiers: AREA_TEXT_AMPLIFIERS
5303
5420
  };
5304
5421
  /**
@@ -5356,7 +5473,7 @@ const GUERRILLA_BASE_METADATA = {
5356
5473
  },
5357
5474
  drawRule: "Area1",
5358
5475
  capturesLabelSize: true,
5359
- params: ECHELON_AREA_PARAMS,
5476
+ params: PREFIXED_ECHELON_AREA_PARAMS,
5360
5477
  textAmplifiers: AREA_TEXT_AMPLIFIERS
5361
5478
  };
5362
5479
  /**
@@ -5474,7 +5591,7 @@ const ASSEMBLY_AREA_METADATA = {
5474
5591
  },
5475
5592
  drawRule: "Area1",
5476
5593
  capturesLabelSize: true,
5477
- params: LABELED_AREA_PARAMS,
5594
+ params: PREFIXED_LABELED_AREA_PARAMS,
5478
5595
  textAmplifiers: AREA_TEXT_AMPLIFIERS
5479
5596
  };
5480
5597
  /**
@@ -6244,10 +6361,7 @@ function battlePositionAreaFeatures(positions, options, textAmplifiers, context,
6244
6361
  const verts = buildClosedRing(positions, smooth, smoothResolution, DEFAULT_SMOOTH_RESOLUTION$6);
6245
6362
  const { strokes, fills, gaps } = placeEchelon(buildAreaPerimeter(verts), h, echelon, echelonPadding, echelonPosition, echelonAnchor);
6246
6363
  const labelFeatures = [];
6247
- const enyGaps = pushAreaLabels(labelFeatures, verts, {
6248
- name: variant.namePrefix ? composeAreaName(variant.namePrefix, textAmplifiers.T) : textAmplifiers.T,
6249
- hostile: textAmplifiers.N
6250
- }, options, context.amplifierPlacements, void 0, context);
6364
+ const enyGaps = pushAreaLabels(labelFeatures, verts, composeAreaLabelTexts(textAmplifiers, variant.namePrefix), options, context.amplifierPlacements, void 0, context);
6251
6365
  const boundaryCoords = buildGappedLine(verts, [...gaps, ...enyGaps]);
6252
6366
  const features = [];
6253
6367
  if (boundaryCoords.length > 0) features.push({
@@ -6368,7 +6482,7 @@ const BATTLE_POSITION_PREPARED_METADATA = {
6368
6482
  },
6369
6483
  drawRule: "Area1",
6370
6484
  capturesLabelSize: true,
6371
- params: ECHELON_AREA_PARAMS,
6485
+ params: PREFIXED_ECHELON_AREA_PARAMS,
6372
6486
  textAmplifiers: AREA_UNIT_DESIGNATION_HOSTILE_AMPLIFIERS
6373
6487
  };
6374
6488
  /**
@@ -7066,6 +7180,7 @@ function calculateBlockArrowGeometry(coordinates, options) {
7066
7180
  ring,
7067
7181
  spine,
7068
7182
  leftSide,
7183
+ rightSide,
7069
7184
  pathLength
7070
7185
  };
7071
7186
  }
@@ -7090,7 +7205,7 @@ const BLOCK_ARROW = defineControlMeasure({
7090
7205
  if (!geometry) return null;
7091
7206
  return {
7092
7207
  spine: geometry.spine,
7093
- leftEdge: geometry.leftSide,
7208
+ rightEdge: geometry.rightSide,
7094
7209
  referenceHalfWidth: geometry.pathLength / 2
7095
7210
  };
7096
7211
  },
@@ -7124,70 +7239,22 @@ function normalizeSmoothResolution$1(value) {
7124
7239
  return Math.min(MAX_SMOOTH_RESOLUTION$1, Math.max(MIN_SMOOTH_RESOLUTION$1, Math.round(value)));
7125
7240
  }
7126
7241
  //#endregion
7127
- //#region src/generators/cm11-command-control-lines/boundary.ts
7128
- const DEFAULT_SMOOTH_RESOLUTION$4 = 12;
7129
- function resolveLabelRepetitions(value) {
7130
- const numeric = Number(value ?? 1);
7131
- return Number.isFinite(numeric) ? Math.max(1, Math.round(numeric)) : 1;
7132
- }
7133
- /** Default options for the Boundary control measure. */
7134
- const DEFAULT_BOUNDARY_OPTIONS = {
7135
- echelon: "battalion",
7136
- echelonSize: 750,
7137
- echelonSizePixels: 16,
7138
- echelonPadding: .3,
7139
- labelRepetitions: 1,
7140
- labelSpacing: 1,
7141
- labelPosition: .5,
7142
- labelPadding: .4,
7143
- labelOrientation: "along",
7144
- smooth: false,
7145
- smoothResolution: DEFAULT_SMOOTH_RESOLUTION$4
7146
- };
7147
- const BOUNDARY_METADATA = {
7148
- id: "boundary",
7149
- name: "Boundary",
7150
- description: "Delineates the area of responsibility between two adjacent units, labeled with the echelon and the designators of the units it separates.",
7151
- entity: "Command and Control Lines",
7152
- entityType: "Boundary",
7153
- value: "110100",
7154
- minCoordinates: 2,
7155
- geometry: "line",
7156
- geometryTypes: [
7157
- "MultiLineString",
7158
- "MultiPolygon",
7159
- "Point"
7160
- ],
7161
- paints: {
7162
- stroke: true,
7163
- fill: "fixed",
7164
- text: true
7165
- },
7166
- drawRule: "Line1",
7167
- params: [
7168
- {
7169
- key: "smooth",
7170
- label: "Smooth",
7171
- description: "Round the boundary's corners by curving it through the control points.",
7172
- type: "boolean"
7173
- },
7174
- {
7175
- key: "smoothResolution",
7176
- presentationTier: "advanced",
7177
- label: "Smooth resolution",
7178
- description: "Number of samples per segment when smooth mode is enabled.",
7179
- type: "number",
7180
- min: 2,
7181
- max: 64,
7182
- step: 1,
7183
- visibleWhen: (opts) => Boolean(opts.smooth)
7184
- },
7242
+ //#region src/internal/line-echelon.ts
7243
+ /**
7244
+ * The echelon and group-distribution controls shared by the line measures that
7245
+ * stamp Field B onto their geometry (Boundary, Generic command and control
7246
+ * line). `subject` names the geometry in the user-facing copy ("line",
7247
+ * "boundary"). Callers spread these into their own `params` and add whatever
7248
+ * else they carry (e.g. Boundary's unit-label padding).
7249
+ */
7250
+ function echelonLineParams(subject) {
7251
+ return [
7185
7252
  {
7186
7253
  key: "echelon",
7187
7254
  presentationTier: "primary",
7188
7255
  semanticRole: "doctrinal",
7189
7256
  label: "Echelon",
7190
- description: "Field B unit-size amplifier, drawn on the line",
7257
+ description: `Field B unit-size amplifier, drawn on the ${subject}`,
7191
7258
  type: "enum",
7192
7259
  options: ECHELON_PARAM_OPTIONS
7193
7260
  },
@@ -7225,7 +7292,7 @@ const BOUNDARY_METADATA = {
7225
7292
  key: "labelRepetitions",
7226
7293
  presentationTier: "advanced",
7227
7294
  label: "Label groups",
7228
- description: "Number of label groups spaced evenly along the whole boundary",
7295
+ description: `Number of label groups spaced evenly along the whole ${subject}`,
7229
7296
  type: "number",
7230
7297
  min: 1,
7231
7298
  max: 5,
@@ -7235,7 +7302,7 @@ const BOUNDARY_METADATA = {
7235
7302
  key: "labelPosition",
7236
7303
  presentationTier: "advanced",
7237
7304
  label: "Label position",
7238
- description: "Position of the label group along the boundary, from the first point (0) to the last (1)",
7305
+ description: `Position of the label group along the ${subject}, from the first point (0) to the last (1)`,
7239
7306
  type: "number",
7240
7307
  min: 0,
7241
7308
  max: 1,
@@ -7252,7 +7319,122 @@ const BOUNDARY_METADATA = {
7252
7319
  max: 2,
7253
7320
  step: .05,
7254
7321
  visibleWhen: (opts) => resolveLabelRepetitions(opts.labelRepetitions) > 1
7322
+ }
7323
+ ];
7324
+ }
7325
+ /** A placement with nothing in it — the result for a degenerate line. */
7326
+ const EMPTY_LINE_ECHELON_PLACEMENT = {
7327
+ strokes: [],
7328
+ fills: [],
7329
+ gaps: [],
7330
+ groups: []
7331
+ };
7332
+ /**
7333
+ * Distributes `labelRepetitions` echelon groups along `verts` and builds the
7334
+ * glyph geometry for each. `spec` may be `undefined` — the groups are still
7335
+ * placed (so a caller can label them) but no glyph or gap is emitted.
7336
+ */
7337
+ function placeEchelonsAlongLine(verts, spec, h, options) {
7338
+ const { labelRepetitions, labelPosition, defaultLabelPosition, labelSpacing, labelOrientation, echelonPadding } = options;
7339
+ const { segments, totalLength } = polylineSegments(verts);
7340
+ if (totalLength < 1e-6) return EMPTY_LINE_ECHELON_PLACEMENT;
7341
+ const reps = resolveLabelRepetitions(labelRepetitions);
7342
+ const singleGroupPosition = clampLinePosition(labelPosition, defaultLabelPosition);
7343
+ const strokes = [];
7344
+ const fills = [];
7345
+ const gaps = [];
7346
+ const groups = [];
7347
+ for (let k = 0; k < reps; k++) {
7348
+ const evenFraction = (k + 1) / (reps + 1);
7349
+ const fraction = Math.min(1, Math.max(0, reps === 1 ? singleGroupPosition : .5 + (evenFraction - .5) * labelSpacing));
7350
+ const target = fraction * totalLength;
7351
+ const { point: center, along, perp } = pointAlongPolyline(segments, totalLength, fraction);
7352
+ const rotateGroup = labelOrientation === "standard" && Math.abs(along[0]) < Math.abs(along[1]);
7353
+ const readingAxis = perp[0] >= 0 ? perp : vecScale(perp, -1);
7354
+ let glyphWidth = 0;
7355
+ if (spec) {
7356
+ const glyph = buildEchelonGlyph(center, rotateGroup ? readingAxis : along, rotateGroup ? [-readingAxis[1], readingAxis[0]] : perp, h, spec);
7357
+ glyphWidth = glyph.width;
7358
+ strokes.push(...glyph.strokes);
7359
+ fills.push(...glyph.fills);
7360
+ const halfGap = (rotateGroup ? h : glyphWidth) / 2 + Math.max(0, echelonPadding) * h;
7361
+ gaps.push({
7362
+ g0: target - halfGap,
7363
+ g1: target + halfGap
7364
+ });
7365
+ }
7366
+ groups.push({
7367
+ center,
7368
+ along,
7369
+ perp,
7370
+ rotateGroup,
7371
+ readingAxis,
7372
+ glyphWidth
7373
+ });
7374
+ }
7375
+ return {
7376
+ strokes,
7377
+ fills,
7378
+ gaps,
7379
+ groups
7380
+ };
7381
+ }
7382
+ //#endregion
7383
+ //#region src/generators/cm11-command-control-lines/boundary.ts
7384
+ const DEFAULT_SMOOTH_RESOLUTION$4 = 12;
7385
+ /** Default options for the Boundary control measure. */
7386
+ const DEFAULT_BOUNDARY_OPTIONS = {
7387
+ echelon: "battalion",
7388
+ echelonSize: 750,
7389
+ echelonSizePixels: 16,
7390
+ echelonPadding: .3,
7391
+ labelRepetitions: 1,
7392
+ labelSpacing: 1,
7393
+ labelPosition: .5,
7394
+ labelPadding: .4,
7395
+ labelOrientation: "along",
7396
+ smooth: false,
7397
+ smoothResolution: DEFAULT_SMOOTH_RESOLUTION$4
7398
+ };
7399
+ const BOUNDARY_METADATA = {
7400
+ id: "boundary",
7401
+ name: "Boundary",
7402
+ description: "Delineates the area of responsibility between two adjacent units, labeled with the echelon and the designators of the units it separates.",
7403
+ entity: "Command and Control Lines",
7404
+ entityType: "Boundary",
7405
+ value: "110100",
7406
+ minCoordinates: 2,
7407
+ geometry: "line",
7408
+ geometryTypes: [
7409
+ "MultiLineString",
7410
+ "MultiPolygon",
7411
+ "Point"
7412
+ ],
7413
+ paints: {
7414
+ stroke: true,
7415
+ fill: "fixed",
7416
+ text: true
7417
+ },
7418
+ drawRule: "Line1",
7419
+ params: [
7420
+ {
7421
+ key: "smooth",
7422
+ label: "Smooth",
7423
+ description: "Round the boundary's corners by curving it through the control points.",
7424
+ type: "boolean"
7425
+ },
7426
+ {
7427
+ key: "smoothResolution",
7428
+ presentationTier: "advanced",
7429
+ label: "Smooth resolution",
7430
+ description: "Number of samples per segment when smooth mode is enabled.",
7431
+ type: "number",
7432
+ min: 2,
7433
+ max: 64,
7434
+ step: 1,
7435
+ visibleWhen: (opts) => Boolean(opts.smooth)
7255
7436
  },
7437
+ ...echelonLineParams("boundary"),
7256
7438
  {
7257
7439
  key: "labelPadding",
7258
7440
  presentationTier: "advanced",
@@ -7318,80 +7500,21 @@ const BOUNDARY_METADATA = {
7318
7500
  */
7319
7501
  function createBoundary(positions, options = {}, textAmplifiers = {}, context = {}) {
7320
7502
  const { echelon = DEFAULT_BOUNDARY_OPTIONS.echelon, echelonSize = DEFAULT_BOUNDARY_OPTIONS.echelonSize, echelonSizePixels, echelonPadding = DEFAULT_BOUNDARY_OPTIONS.echelonPadding, metersPerPixel, labelRepetitions = DEFAULT_BOUNDARY_OPTIONS.labelRepetitions, labelSpacing = DEFAULT_BOUNDARY_OPTIONS.labelSpacing, labelPosition = DEFAULT_BOUNDARY_OPTIONS.labelPosition, labelPadding = DEFAULT_BOUNDARY_OPTIONS.labelPadding, labelOrientation = DEFAULT_BOUNDARY_OPTIONS.labelOrientation, smooth = DEFAULT_BOUNDARY_OPTIONS.smooth, smoothResolution = DEFAULT_BOUNDARY_OPTIONS.smoothResolution } = options;
7321
- const unit1Designator = textAmplifiers.T ?? "";
7322
- const unit1Country = textAmplifiers.AS ?? "";
7323
- const unit2Designator = textAmplifiers.T1 ?? "";
7324
- const unit2Country = textAmplifiers.AS1 ?? "";
7325
- let h = echelonSize;
7326
- if (echelonSizePixels !== void 0 && metersPerPixel !== void 0 && metersPerPixel > 0) h = echelonSizePixels * metersPerPixel;
7327
- h = Math.max(EPSILON, h);
7328
- const reps = resolveLabelRepetitions(labelRepetitions);
7329
- const singleGroupPosition = clampLinePosition(labelPosition, DEFAULT_BOUNDARY_OPTIONS.labelPosition);
7503
+ const h = resolveEchelonHeight(echelonSize, echelonSizePixels, metersPerPixel);
7330
7504
  const spec = resolveEchelon(echelon);
7331
- const screenAnchored = echelonSizePixels !== void 0 && metersPerPixel !== void 0 && metersPerPixel > 0;
7332
- const labelSize = screenAnchored ? { textSizePixels: echelonSizePixels } : { textSizeMeters: h };
7505
+ const { properties: labelSize, screenAnchored } = echelonUnitLabelSize(h, echelonSizePixels, metersPerPixel);
7333
7506
  const rawVerts = positions.map((p) => project(p[0], p[1]));
7334
7507
  const verts = smooth ? catmullRom(rawVerts, normalizeSmoothResolution$2(smoothResolution, DEFAULT_SMOOTH_RESOLUTION$4)) : rawVerts;
7335
- const glyphStrokes = [];
7336
- const glyphFills = [];
7337
7508
  const labelFeatures = [];
7338
- const gaps = [];
7339
- const { segments: segs, totalLength } = polylineSegments(verts);
7340
- if (totalLength >= 1e-6) for (let k = 0; k < reps; k++) {
7341
- const evenFraction = (k + 1) / (reps + 1);
7342
- const fraction = Math.min(1, Math.max(0, reps === 1 ? singleGroupPosition : .5 + (evenFraction - .5) * labelSpacing));
7343
- const target = fraction * totalLength;
7344
- const frame = pointAlongPolyline(segs, totalLength, fraction);
7345
- const center = frame.point;
7346
- const seg = {
7347
- along: frame.along,
7348
- perp: frame.perp
7349
- };
7350
- const units = [{
7351
- side: 1,
7352
- designator: unit1Designator,
7353
- country: unit1Country
7354
- }, {
7355
- side: -1,
7356
- designator: unit2Designator,
7357
- country: unit2Country
7358
- }];
7359
- const rotateGroup = labelOrientation === "standard" && Math.abs(seg.along[0]) < Math.abs(seg.along[1]);
7360
- const readingAxis = seg.perp[0] >= 0 ? seg.perp : vecScale(seg.perp, -1);
7361
- const glyphAlong = rotateGroup ? readingAxis : seg.along;
7362
- const glyphPerp = rotateGroup ? [-readingAxis[1], readingAxis[0]] : seg.perp;
7363
- let glyphWidth = 0;
7364
- if (spec) {
7365
- const { strokes, fills, width } = buildEchelonGlyph(center, glyphAlong, glyphPerp, h, spec);
7366
- glyphWidth = width;
7367
- glyphStrokes.push(...strokes);
7368
- glyphFills.push(...fills);
7369
- const halfGap = (rotateGroup ? h : width) / 2 + Math.max(0, echelonPadding) * h;
7370
- gaps.push({
7371
- g0: target - halfGap,
7372
- g1: target + halfGap
7373
- });
7374
- }
7375
- if (rotateGroup) {
7376
- const sign = vecDot(seg.perp, readingAxis) >= 0 ? 1 : -1;
7377
- const clearance = glyphWidth / 2 + Math.max(0, labelPadding) * h;
7378
- units[0].textAnchor = sign > 0 ? "start" : "end";
7379
- units[1].textAnchor = sign > 0 ? "end" : "start";
7380
- pushUnitLabels(labelFeatures, {
7381
- center,
7382
- perp: vecScale(readingAxis, sign),
7383
- offset: clearance,
7384
- rotation: labelRotationAlong(readingAxis),
7385
- labelSize
7386
- }, units);
7387
- } else pushUnitLabels(labelFeatures, {
7388
- center,
7389
- perp: seg.perp,
7390
- offset: (.45 + Math.max(0, labelPadding)) * h,
7391
- rotation: labelRotationAlong(seg.along),
7392
- labelSize
7393
- }, units);
7394
- }
7509
+ const { strokes: glyphStrokes, fills: glyphFills, gaps, groups } = placeEchelonsAlongLine(verts, spec, h, {
7510
+ labelRepetitions,
7511
+ labelPosition,
7512
+ defaultLabelPosition: DEFAULT_BOUNDARY_OPTIONS.labelPosition,
7513
+ labelSpacing,
7514
+ labelOrientation,
7515
+ echelonPadding
7516
+ });
7517
+ pushEchelonUnitLabels(labelFeatures, groups, unitLabelsFromAmplifiers(textAmplifiers), h, labelPadding, labelSize);
7395
7518
  const hostileLabelOptions = screenAnchored ? {
7396
7519
  labelSizePixels: echelonSizePixels,
7397
7520
  metersPerPixel,
@@ -7678,8 +7801,26 @@ const ENGINEER_WORK_LINE = defineControlMeasure({
7678
7801
  });
7679
7802
  //#endregion
7680
7803
  //#region src/generators/cm11-command-control-lines/generic-c2-line.ts
7804
+ const GENERIC_C2_UNIT_LABEL_FIELDS = {
7805
+ unit1: {
7806
+ designator: "T1",
7807
+ country: "AS1"
7808
+ },
7809
+ unit2: {
7810
+ designator: "T2",
7811
+ country: "AS2"
7812
+ }
7813
+ };
7681
7814
  /** Default options for the Generic command and control line. */
7682
7815
  const DEFAULT_GENERIC_C2_LINE_OPTIONS = {
7816
+ echelon: "none",
7817
+ echelonSize: 750,
7818
+ echelonSizePixels: 16,
7819
+ echelonPadding: .3,
7820
+ labelRepetitions: 1,
7821
+ labelSpacing: 1,
7822
+ labelPosition: .5,
7823
+ labelOrientation: "along",
7683
7824
  includePrefix: true,
7684
7825
  smooth: false,
7685
7826
  smoothResolution: 12
@@ -7687,22 +7828,42 @@ const DEFAULT_GENERIC_C2_LINE_OPTIONS = {
7687
7828
  const GENERIC_C2_LINE_METADATA = {
7688
7829
  id: "generic-c2-line",
7689
7830
  name: "Generic command and control line",
7690
- description: "Illustrative command-and-control-style line (not part of MIL-STD-2525E) carrying optional additional-information/designation text above it and an effective date-time-group window below it.",
7831
+ description: "Illustrative command-and-control-style line (not part of MIL-STD-2525E) carrying optional echelon glyphs, additional-information/designation text above it, and an effective date-time-group window below it.",
7691
7832
  entity: "Command and Control Lines",
7692
7833
  entityType: "Generic",
7693
7834
  value: "110400",
7694
7835
  minCoordinates: 2,
7695
7836
  geometry: "line",
7696
- geometryTypes: ["LineString", "Point"],
7837
+ geometryTypes: [
7838
+ "LineString",
7839
+ "MultiLineString",
7840
+ "MultiPolygon",
7841
+ "Point"
7842
+ ],
7697
7843
  paints: {
7698
7844
  stroke: true,
7699
- fill: "none",
7845
+ fill: "fixed",
7700
7846
  text: true
7701
7847
  },
7702
7848
  drawRule: "Line1",
7703
7849
  capturesLabelSize: true,
7704
7850
  params: [
7705
7851
  ...SMOOTH_LINE_PARAMS,
7852
+ ...echelonLineParams("line"),
7853
+ {
7854
+ key: "labelOrientation",
7855
+ presentationTier: "advanced",
7856
+ label: "Label orientation",
7857
+ description: "Orient the echelon along the line or perpendicular on mostly north-south segments.",
7858
+ type: "enum",
7859
+ options: [{
7860
+ value: "along",
7861
+ label: "Along the line"
7862
+ }, {
7863
+ value: "standard",
7864
+ label: "Standard (MIL-STD-2525E)"
7865
+ }]
7866
+ },
7706
7867
  {
7707
7868
  key: "phaseLineName",
7708
7869
  presentationTier: "primary",
@@ -7745,6 +7906,30 @@ const GENERIC_C2_LINE_METADATA = {
7745
7906
  description: "Field T — unique designation of the line, shown above it near each end.",
7746
7907
  maxLength: 21
7747
7908
  },
7909
+ {
7910
+ key: "T1",
7911
+ label: "Unit 1 designation",
7912
+ description: "Field T1 — designation of unit 1 on the left-of-travel side.",
7913
+ maxLength: 32
7914
+ },
7915
+ {
7916
+ key: "AS1",
7917
+ label: "Unit 1 country",
7918
+ description: "Field AS1 — country code of unit 1 on the left-of-travel side.",
7919
+ maxLength: 8
7920
+ },
7921
+ {
7922
+ key: "T2",
7923
+ label: "Unit 2 designation",
7924
+ description: "Field T2 — designation of unit 2 on the right-of-travel side.",
7925
+ maxLength: 32
7926
+ },
7927
+ {
7928
+ key: "AS2",
7929
+ label: "Unit 2 country",
7930
+ description: "Field AS2 — country code of unit 2 on the right-of-travel side.",
7931
+ maxLength: 8
7932
+ },
7748
7933
  {
7749
7934
  key: "W",
7750
7935
  label: "Effective from (DTG)",
@@ -7770,19 +7955,66 @@ const GENERIC_C2_LINE_METADATA = {
7770
7955
  * `base + perp·offset` and the other at `base − perp·offset`.
7771
7956
  */
7772
7957
  function createGenericC2Line(positions, options = {}, textAmplifiers = {}, context = {}) {
7773
- const { phaseLineName, includePrefix = true, smooth, smoothResolution, ...sizeOptions } = options;
7958
+ const { echelon = DEFAULT_GENERIC_C2_LINE_OPTIONS.echelon, echelonSize = DEFAULT_GENERIC_C2_LINE_OPTIONS.echelonSize, echelonSizePixels, echelonPadding = DEFAULT_GENERIC_C2_LINE_OPTIONS.echelonPadding, labelRepetitions = DEFAULT_GENERIC_C2_LINE_OPTIONS.labelRepetitions, labelSpacing = DEFAULT_GENERIC_C2_LINE_OPTIONS.labelSpacing, labelPosition = DEFAULT_GENERIC_C2_LINE_OPTIONS.labelPosition, labelOrientation = DEFAULT_GENERIC_C2_LINE_OPTIONS.labelOrientation, phaseLineName, includePrefix = true, smooth, smoothResolution, ...sizeOptions } = options;
7774
7959
  const verts = smoothLineVerts(positions.map((p) => project(p[0], p[1])), {
7775
7960
  smooth,
7776
7961
  smoothResolution
7777
7962
  }, 12);
7778
- const features = [{
7963
+ const features = [];
7964
+ const spec = resolveEchelon(echelon);
7965
+ const h = resolveEchelonHeight(echelonSize, echelonSizePixels, sizeOptions.metersPerPixel);
7966
+ const { strokes: glyphStrokes, fills: glyphFills, gaps, groups } = spec ? placeEchelonsAlongLine(verts, spec, h, {
7967
+ labelRepetitions,
7968
+ labelPosition,
7969
+ defaultLabelPosition: DEFAULT_GENERIC_C2_LINE_OPTIONS.labelPosition,
7970
+ labelSpacing,
7971
+ labelOrientation,
7972
+ echelonPadding
7973
+ }) : EMPTY_LINE_ECHELON_PLACEMENT;
7974
+ const gappedCoordinates = gaps.length > 0 ? buildGappedLine(verts, gaps) : [];
7975
+ if (gappedCoordinates.length > 0) features.push({
7976
+ type: "Feature",
7977
+ properties: { part: "generic-c2-line" },
7978
+ geometry: {
7979
+ type: "MultiLineString",
7980
+ coordinates: gappedCoordinates
7981
+ }
7982
+ });
7983
+ else if (gaps.length === 0) features.push({
7779
7984
  type: "Feature",
7780
7985
  properties: { part: "generic-c2-line" },
7781
7986
  geometry: {
7782
7987
  type: "LineString",
7783
7988
  coordinates: smooth ? verts.map((v) => unproject(v[0], v[1])) : positions
7784
7989
  }
7785
- }];
7990
+ });
7991
+ if (glyphStrokes.length > 0) features.push({
7992
+ type: "Feature",
7993
+ properties: { part: "echelon" },
7994
+ geometry: {
7995
+ type: "MultiLineString",
7996
+ coordinates: glyphStrokes
7997
+ }
7998
+ });
7999
+ if (glyphFills.length > 0) features.push({
8000
+ type: "Feature",
8001
+ properties: {
8002
+ part: "echelon",
8003
+ fill: true,
8004
+ style: SOLID_ACCENT_FILL
8005
+ },
8006
+ geometry: {
8007
+ type: "MultiPolygon",
8008
+ coordinates: glyphFills.map((ring) => [ring])
8009
+ }
8010
+ });
8011
+ if (Boolean(textAmplifiers.T1 || textAmplifiers.AS1 || textAmplifiers.T2 || textAmplifiers.AS2) && groups.length > 0) {
8012
+ const unitLabels = [];
8013
+ const units = unitLabelsFromAmplifiers(textAmplifiers, GENERIC_C2_UNIT_LABEL_FIELDS);
8014
+ const { properties: labelSize } = echelonUnitLabelSize(h, echelonSizePixels, sizeOptions.metersPerPixel);
8015
+ pushEchelonUnitLabels(unitLabels, groups, units, h, sizeOptions.labelPadding ?? .4, labelSize);
8016
+ features.push(...unitLabels);
8017
+ }
7786
8018
  const above = [textAmplifiers.H, textAmplifiers.T].filter((v) => Boolean(v)).join(" ");
7787
8019
  const below = [textAmplifiers.W, textAmplifiers.W1].filter((v) => Boolean(v)).join(" - ");
7788
8020
  const trimmedPhaseLineName = phaseLineName?.trim();
@@ -11224,7 +11456,7 @@ const DROP_ZONE_METADATA = {
11224
11456
  },
11225
11457
  drawRule: "Area1",
11226
11458
  capturesLabelSize: true,
11227
- params: LABELED_AREA_PARAMS,
11459
+ params: PREFIXED_LABELED_AREA_PARAMS,
11228
11460
  textAmplifiers: AREA_TEXT_AMPLIFIERS_DESIGNATION_HOSTILE
11229
11461
  };
11230
11462
  /**
@@ -11441,7 +11673,7 @@ const EXTRACTION_ZONE_METADATA = {
11441
11673
  },
11442
11674
  drawRule: "Area1",
11443
11675
  capturesLabelSize: true,
11444
- params: LABELED_AREA_PARAMS,
11676
+ params: PREFIXED_LABELED_AREA_PARAMS,
11445
11677
  textAmplifiers: AREA_TEXT_AMPLIFIERS_DESIGNATION_HOSTILE
11446
11678
  };
11447
11679
  /**
@@ -14214,7 +14446,7 @@ const JOINT_TACTICAL_ACTION_AREA_METADATA = {
14214
14446
  },
14215
14447
  drawRule: "Area1",
14216
14448
  capturesLabelSize: true,
14217
- params: LABELED_AREA_PARAMS,
14449
+ params: PREFIXED_LABELED_AREA_PARAMS,
14218
14450
  textAmplifiers: AREA_TEXT_AMPLIFIERS
14219
14451
  };
14220
14452
  /**
@@ -14274,7 +14506,7 @@ const LANDING_ZONE_METADATA = {
14274
14506
  },
14275
14507
  drawRule: "Area1",
14276
14508
  capturesLabelSize: true,
14277
- params: LABELED_AREA_PARAMS,
14509
+ params: PREFIXED_LABELED_AREA_PARAMS,
14278
14510
  textAmplifiers: AREA_TEXT_AMPLIFIERS
14279
14511
  };
14280
14512
  /**
@@ -15574,7 +15806,7 @@ const PICKUP_ZONE_METADATA = {
15574
15806
  },
15575
15807
  drawRule: "Area1",
15576
15808
  capturesLabelSize: true,
15577
- params: LABELED_AREA_PARAMS,
15809
+ params: PREFIXED_LABELED_AREA_PARAMS,
15578
15810
  textAmplifiers: AREA_TEXT_AMPLIFIERS
15579
15811
  };
15580
15812
  /**
@@ -15629,7 +15861,7 @@ const ASSAULT_POSITION_METADATA = {
15629
15861
  },
15630
15862
  drawRule: "Area1",
15631
15863
  capturesLabelSize: true,
15632
- params: LABELED_AREA_PARAMS,
15864
+ params: PREFIXED_LABELED_AREA_PARAMS,
15633
15865
  textAmplifiers: AREA_TEXT_AMPLIFIERS_DESIGNATION_HOSTILE
15634
15866
  };
15635
15867
  /**
@@ -15684,7 +15916,7 @@ const ATTACK_POSITION_METADATA = {
15684
15916
  },
15685
15917
  drawRule: "Area1",
15686
15918
  capturesLabelSize: true,
15687
- params: LABELED_AREA_PARAMS,
15919
+ params: PREFIXED_LABELED_AREA_PARAMS,
15688
15920
  textAmplifiers: AREA_TEXT_AMPLIFIERS_DESIGNATION_HOSTILE
15689
15921
  };
15690
15922
  /**
@@ -15739,7 +15971,7 @@ const OBJECTIVE_AREA_METADATA = {
15739
15971
  },
15740
15972
  drawRule: "Area1",
15741
15973
  capturesLabelSize: true,
15742
- params: LABELED_AREA_PARAMS,
15974
+ params: PREFIXED_LABELED_AREA_PARAMS,
15743
15975
  textAmplifiers: AREA_TEXT_AMPLIFIERS_DESIGNATION_HOSTILE
15744
15976
  };
15745
15977
  /**
@@ -16302,7 +16534,7 @@ const SUBMARINE_ACTION_AREA_METADATA = {
16302
16534
  },
16303
16535
  drawRule: "Area1",
16304
16536
  capturesLabelSize: true,
16305
- params: LABELED_AREA_PARAMS,
16537
+ params: PREFIXED_LABELED_AREA_PARAMS,
16306
16538
  textAmplifiers: AREA_TEXT_AMPLIFIERS_NO_ADDITIONAL_INFO
16307
16539
  };
16308
16540
  /**
@@ -16362,7 +16594,7 @@ const SUBMARINE_GENERATED_ACTION_AREA_METADATA = {
16362
16594
  },
16363
16595
  drawRule: "Area1",
16364
16596
  capturesLabelSize: true,
16365
- params: LABELED_AREA_PARAMS,
16597
+ params: PREFIXED_LABELED_AREA_PARAMS,
16366
16598
  textAmplifiers: AREA_TEXT_AMPLIFIERS_NO_ADDITIONAL_INFO
16367
16599
  };
16368
16600
  /**
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Area of operations"><rect x="0" y="0" width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M10.00 43.00 L86.00 43.00 L86.00 5.00 L10.00 5.00 L10.00 43.00 Z" fill="#1e293b" fill-opacity="0" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><g transform="rotate(0.000 48.000 24.000)"><text x="48" y="24" fill="#1e293b" font-family="sans-serif" font-size="6.554078332734459" font-weight="600" text-anchor="middle" dominant-baseline="central">AO GREEN</text></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Area of operations"><rect x="0" y="0" width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M10.00 43.00 L86.00 43.00 L86.00 5.00 L10.00 5.00 L10.00 43.00 Z" fill="#1e293b" fill-opacity="0" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><g transform="rotate(0.000 48.000 24.000)"><text x="48" y="24" fill="#1e293b" font-family="sans-serif" font-size="6.554078332734459" font-weight="600" text-anchor="middle" dominant-baseline="central"><tspan x="48" y="20.067553000359325">AO</tspan><tspan x="48" y="27.932446999640675">GREEN</tspan></text></g></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Bridge or Gap"><rect x="0" y="0" width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M34.72 43.00 L40.71 37.01 L40.71 13.05 L34.72 7.06" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M61.28 43.00 L55.29 37.01 L55.29 13.05 L61.28 7.06" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><g transform="rotate(270.000 48.000 25.031)"><text x="48" y="25.031363088057898" fill="#1e293b" font-family="sans-serif" font-size="2.0588555277236815" font-weight="600" text-anchor="middle" dominant-baseline="central">T</text></g><g transform="rotate(0.000 47.692 5.000)"><text x="47.691632854479664" y="5" fill="#1e293b" font-family="sans-serif" font-size="2.0588555277236815" font-weight="600" text-anchor="end" dominant-baseline="central">W</text></g><g transform="rotate(0.000 48.308 5.000)"><text x="48.30836714552034" y="5" fill="#1e293b" font-family="sans-serif" font-size="2.0588555277236815" font-weight="600" text-anchor="start" dominant-baseline="central">W1</text></g></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Envelopment"><rect x="0" y="0" width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M5.00 35.88 L23.17 35.88" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M29.58 35.88 L40.64 35.88" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M40.64 35.88 L40.75 33.55 L41.09 31.24 L41.66 28.98 L42.44 26.78 L43.44 24.68 L44.64 22.68 L46.02 20.81 L47.59 19.08 L49.32 17.51 L51.19 16.12 L53.20 14.92 L55.30 13.93 L57.49 13.15 L59.75 12.58 L62.06 12.24 L64.39 12.12 L66.72 12.24 L69.03 12.58 L71.29 13.15 L73.49 13.93 L75.59 14.92 L77.59 16.12 L79.46 17.51 L81.19 19.08 L82.76 20.81 L84.15 22.68 L85.35 24.68 L86.34 26.78 L87.12 28.98 L87.69 31.24 L88.04 33.55 L88.15 35.88" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M91.00 31.13 L88.15 35.88 L85.30 31.13" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><g transform="rotate(0.000 26.381 35.878)"><text x="26.38121546961327" y="35.87845303867403" fill="#1e293b" font-family="sans-serif" font-size="7.68" font-weight="600" text-anchor="middle" dominant-baseline="central">E</text></g></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Generic command and control line"><rect x="0" y="0" width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M5.00 24.00 L91.00 24.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><g transform="rotate(0.000 7.226 19.549)"><text x="7.2256800000000005" y="19.54864" fill="#1e293b" font-family="sans-serif" font-size="7.416457060725835" font-weight="600" text-anchor="start" dominant-baseline="central"><H> <T></text></g><g transform="rotate(0.000 7.226 28.451)"><text x="7.2256800000000005" y="28.45136" fill="#1e293b" font-family="sans-serif" font-size="6.193548387096775" font-weight="600" text-anchor="start" dominant-baseline="central"><W> - <W1></text></g><g transform="rotate(0.000 88.774 19.549)"><text x="88.77432" y="19.54864" fill="#1e293b" font-family="sans-serif" font-size="7.416457060725835" font-weight="600" text-anchor="end" dominant-baseline="central"><H> <T></text></g><g transform="rotate(0.000 88.774 28.451)"><text x="88.77432" y="28.45136" fill="#1e293b" font-family="sans-serif" font-size="6.193548387096775" font-weight="600" text-anchor="end" dominant-baseline="central"><W> - <W1></text></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Generic command and control line"><rect x="0" y="0" width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M5.00 24.00 L91.00 24.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><g transform="rotate(0.000 7.226 19.549)"><text x="7.2256800000000005" y="19.54864" fill="#1e293b" font-family="sans-serif" font-size="7.416457060725835" font-weight="600" text-anchor="start" dominant-baseline="central">&lt;H&gt; &lt;T&gt;</text></g><g transform="rotate(0.000 7.226 28.451)"><text x="7.2256800000000005" y="28.45136" fill="#1e293b" font-family="sans-serif" font-size="6.193548387096775" font-weight="600" text-anchor="start" dominant-baseline="central">&lt;W&gt; - &lt;W1&gt;</text></g><g transform="rotate(0.000 88.774 19.549)"><text x="88.77432" y="19.54864" fill="#1e293b" font-family="sans-serif" font-size="7.416457060725835" font-weight="600" text-anchor="end" dominant-baseline="central">&lt;H&gt; &lt;T&gt;</text></g><g transform="rotate(0.000 88.774 28.451)"><text x="88.77432" y="28.45136" fill="#1e293b" font-family="sans-serif" font-size="6.193548387096775" font-weight="600" text-anchor="end" dominant-baseline="central">&lt;W&gt; - &lt;W1&gt;</text></g></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Infiltration"><rect x="0" y="0" width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M5.00 9.82 L18.76 9.82" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M25.64 9.82 L33.67 9.82" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M33.67 9.82 L34.84 9.88 L36.00 10.05 L37.14 10.34 L38.23 10.73 L39.29 11.24 L40.30 11.84 L41.24 12.54 L42.11 13.32 L42.90 14.19 L43.59 15.14 L44.20 16.14 L44.70 17.20 L45.10 18.30 L45.38 19.44 L45.55 20.59 L45.61 21.77" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M45.61 21.77 L45.67 22.94 L45.84 24.10 L46.13 25.24 L46.52 26.34 L47.03 27.40 L47.63 28.40 L48.32 29.35 L49.11 30.22 L49.98 31.00 L50.92 31.70 L51.93 32.30 L52.99 32.81 L54.09 33.20 L55.22 33.48 L56.38 33.66 L57.56 33.71" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M57.56 33.71 L91.00 33.71" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M82.08 29.25 L91.00 33.71 L82.08 38.18" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><g transform="rotate(360.000 22.200 9.824)"><text x="22.200000000000003" y="9.824333333333334" fill="#1e293b" font-family="sans-serif" font-size="7.68" font-weight="600" text-anchor="middle" dominant-baseline="central">IN</text></g></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Turning Movement"><rect x="0" y="0" width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M27.99 25.20 L41.03 15.42 L62.42 10.08 L61.15 5.00 L71.94 15.79 L67.49 30.39 L66.22 25.31 L47.91 29.89 L37.41 37.77" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M24.06 19.97 L41.34 43.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><g transform="rotate(345.964 68.507 16.645)"><text x="68.50665978316985" y="16.645224574083635" fill="#1e293b" font-family="sans-serif" font-size="2.81968608360629" font-weight="600" text-anchor="middle" dominant-baseline="central">T</text></g><g transform="rotate(323.130 39.735 26.207)"><text x="39.73495095508518" y="26.207021166752714" fill="#1e293b" font-family="sans-serif" font-size="2.81968608360629" font-weight="600" text-anchor="middle" dominant-baseline="central">DAVID</text></g><g transform="rotate(345.964 50.976 19.431)"><text x="50.97604543107899" y="19.430975735673723" fill="#1e293b" font-family="sans-serif" font-size="2.81968608360629" font-weight="600" text-anchor="middle" dominant-baseline="central">080400Z</text></g><g transform="rotate(345.964 51.729 22.440)"><text x="51.72937532266391" y="22.440371708828085" fill="#1e293b" font-family="sans-serif" font-size="2.81968608360629" font-weight="600" text-anchor="middle" dominant-baseline="central">120300Z</text></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Turning Movement"><rect x="0" y="0" width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M23.26 27.99 L38.10 16.86 L62.44 10.78 L60.99 5.00 L73.27 17.28 L68.22 33.89 L66.77 28.11 L45.94 33.32 L33.99 42.29" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M22.73 27.27 L34.52 43.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><g transform="rotate(345.964 69.371 18.252)"><text x="69.3708142403948" y="18.251556808835623" fill="#1e293b" font-family="sans-serif" font-size="3.2086311502440275" font-weight="600" text-anchor="middle" dominant-baseline="central">T</text></g><g transform="rotate(323.130 36.630 29.132)"><text x="36.63036070966983" y="29.132299377276468" fill="#1e293b" font-family="sans-serif" font-size="3.2086311502440275" font-weight="600" text-anchor="middle" dominant-baseline="central">DAVID</text></g><g transform="rotate(345.964 49.422 21.422)"><text x="49.42204206321231" y="21.421572083186465" fill="#1e293b" font-family="sans-serif" font-size="3.2086311502440275" font-weight="600" text-anchor="middle" dominant-baseline="central">080400Z</text></g><g transform="rotate(345.964 50.279 24.846)"><text x="50.279285630360704" y="24.846081541534485" fill="#1e293b" font-family="sans-serif" font-size="3.2086311502440275" font-weight="600" text-anchor="middle" dominant-baseline="central">120300Z</text></g></svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orbat-mapper/control-measures",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
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",