/// <summary> /// Disconnect from Echelon, enabling ConnectToEchelon to be called again. /// </summary> public static void DestroyEchelonCommunicator() { if (Echelon != null) { Echelon.Disconnect(); Echelon = null; } }
/// <summary> /// Generate the feint dummy rendering for the passed in symbol. /// </summary> /// <param name="ms"> /// The military symbol for which to provide the feint dummy rendering. /// </param> /// <param name="height"> /// The height at which to provide the feint dummy rendering. /// </param> /// <returns> /// The graphics Path object that represents the feint dummy rendering. /// </returns> private static Path GenerateFeintDummy(MilSymbol ms, ref double height) { if (!string.IsNullOrEmpty(Echelon.GetEchelonSymbol(ms.SymbolCode))) { height = ms.Bounds.Top; } if (SymbolData.IsTopFlat(ms.SymbolCode)) { double minimum = ms.BaseRect.Top; if (height >= minimum) { height = minimum - 28; } } double bottom = height + 23; height = height - 27; const double Wide = 126; var st = new Style(typeof(Shape)) { BasedOn = SymbolData.GetStyle("BS10") }; st.SetDashArray(3, 1); return(new Path { Style = st, Data = new PathGeometry { Figures = new PathFigureCollection { new PathFigure { StartPoint = new Point(-Wide, bottom), Segments = new PathSegmentCollection { new LineSegment { Point = new Point(0.0, height) }, new LineSegment { Point = new Point(Wide, bottom) } } } } } }); }
/// <summary> /// Get the combined modifier code for the coding scheme. /// </summary> /// <param name="symbolCode">the symbol code</param> /// <returns>a friendly name for the combined modifier code</returns> public static string GetName(string symbolCode) { if (!SymbolData.Check(ref symbolCode)) { return(string.Empty); } char leadCode = ModifierCode.GetCode(symbolCode); char trailCode = Echelon.GetCode(symbolCode); if (leadCode == ModifierCode.Mobility || leadCode == ModifierCode.Towed) { return(Mobility.GetName(symbolCode)); } if (leadCode == ModifierCode.Installation) { return((trailCode == 'B') ? "Feint Dummy Installation" : "Installation"); } string mod = ModifierCode.GetName(symbolCode); string ech = Echelon.GetName(symbolCode); if (string.IsNullOrEmpty(mod) || string.IsNullOrEmpty(ech)) { return(string.Empty); } if (mod == "None" && ech == "None") { return(string.Empty); } if (mod == "None") { return(ech); } if (ech == "None") { return(mod); } return(mod + "\n" + ech); }
public void EchelonTest() { char gc = Echelon.GetCode(string.Empty); Assert.AreEqual(gc, (char)0); gc = Echelon.GetCode(null); Assert.AreEqual(gc, (char)0); gc = Echelon.GetCode("qqqqqqqqqqqqqqq"); Assert.AreEqual(gc, 'Q'); string str = Echelon.GetName(string.Empty); Assert.AreEqual(str, string.Empty); str = Echelon.GetName(null); Assert.AreEqual(str, string.Empty); str = Echelon.GetName("qqqqqqqqqqqqqqq"); Assert.AreEqual(str, string.Empty); str = Echelon.GetName("qqpqqqqqqqqhqqq"); Assert.AreEqual(str, "Brigade"); }
/// <summary> /// Always generates the entire symbol. /// The symbol code should not change very often. /// </summary> private void GenerateSymbol() { try { // Only draw after we have the symbol code, if drawing via method call if (this.suppressRefresh) { return; } string symbolCode = this.SymbolCode; // Reinitialize this.IsDirty = true; // set a dirty flag to indicate the symbol needs updating this.bounds = Rect.Empty; this.BaseRect = Rect.Empty; this.Children.Clear(); // tried to cheap this one out - but that doesn't work well this.elements.Clear(); // Get the base symbol from "the" resource dictionary var baseSymbol = new MilSymbolBase(symbolCode, this.LineBrush, this.FillBrush); if (baseSymbol.Empty) { return; } this.AddChild("Base", baseSymbol); var styles = MilLabels.GetStyles(this.LabelStyle); // There is only label decoration for weather codes int schemeKey = CodingScheme.GetCode(symbolCode); if (schemeKey == CodingScheme.Weather || schemeKey == CodingScheme.TacticalGraphics) { this.GenerateLabels(styles); return; } // Add in the echelon marking. // "high" is the maximum height from the decoration this.high = Echelon.Generate(this, symbolCode); // Draw headquarters, feint dummy, task force, and installation. // "high" is the maximum height from the decoration this.high = MilHats.Generate(this, symbolCode); // Take care of any Joker, Faker, or Exercise character this.AddChild( "JFE", MilLabels.GenerateJokerFakerExercise(symbolCode, this.labels, styles[MilLabels.BigLabels])); // Add the black ribbon on the base symbol for space this.AddChild("Space", MilSymbolBase.GenerateSpace(symbolCode)); // Indicate whether the entity is damaged or destroyed this.AddChild("OC", StatusOperationalCapacity.Generate(symbolCode)); // Add the mobility to the base of the symbol this.AddChild("Mobility", DrawMobility.GenerateMobility(symbolCode)); // We have to (re)generate the labels because the symbol code extent may be different this.GenerateLabels(styles); } catch (Exception ex) { Log.WriteMessage(LogLevel.Error, "Unable to construct military symbol", ex); } }
/// <summary> /// The main zone generating method. /// </summary> /// <param name="mg"> /// The MilGraphic associated with the zone to be generated. /// </param> /// <param name="isClosed"> /// Whether or not the zone outline is to be closed since this method can be used for polylines as well. /// </param> /// <param name="count"> /// The count of the map locations making up the zone. /// </param> /// <param name="anchors"> /// The map locations making up the zone. /// </param> /// <param name="pointAnchors"> /// The locations in ResourceDictionary space. /// </param> /// <returns> /// A Path representing the map locations, to be associated with the MilGraphic. /// </returns> public static Path GenerateLines( MilGraphic mg, bool isClosed, // do we close the boundary int count, // the number of transformed points to use in boundary IList <ILocation> anchors, out IList <Point> pointAnchors) { IList <Point> pointCp1 = null; IList <Point> pointCp2 = null; pointAnchors = MapHelper.LatLonsToPixels(anchors, 2.0); // Need to convert the cardinal spline points into Bezier spline control points if (mg.IsSpline) { ClosedBezierSpline.GetCurveControlPoints(count, pointAnchors, out pointCp1, out pointCp2); } ScaleData(pointAnchors, pointCp1, pointCp2); // Generate Bezier or line segments for insertion into a figure collection PathFigureCollection figures; if (mg.IsSpline) { figures = new PathFigureCollection { new PathFigure { Segments = GenerateBezierSegments(count, pointAnchors, pointCp1, pointCp2, isClosed) } }; } else { switch (mg.StencilType) { case "ObstacleZone": case "ObstacleBelt": pointAnchors.Add(pointAnchors[0]); figures = MilLine.GenerateDecoratedSegments( mg, DecoratedType.Triangular, false, count + 1, pointAnchors); pointAnchors.RemoveAt(count); break; case "ObstacleRestrictedArea": case "ObstacleFreeArea": pointAnchors.Add(pointAnchors[0]); figures = MilLine.GenerateDecoratedSegments( mg, DecoratedType.Triangular, true, count + 1, pointAnchors); pointAnchors.RemoveAt(count); break; case "Boundaries": figures = MilLine.GenerateDecoratedSegments(mg, DecoratedType.Echelon, true, count, pointAnchors); var labels = new[] { mg.LabelT, Echelon.GetEchelonSymbol(mg.SymbolCode), mg.LabelT1 }; int figureCount = figures.Count; for (int i = 0; i < figureCount - 1; i++) { var pls = figures[i].Segments[0] as PolyLineSegment; if (pls == null) { continue; } var pc = pls.Points.Count - 1; if (pc > 0) { mg.AddChild( "Label" + i, MilLine.GenerateLabels( mg, labels, pls.Points[pc], pls.Points[pc - 1], pointAnchors[0], new Point(1.0, 0.5))); } } break; default: figures = new PathFigureCollection { new PathFigure { Segments = GeneratePolygonSegments(count, pointAnchors) } }; break; } } // In most cases we have a single figure figures[0].StartPoint = pointAnchors[0]; figures[0].IsClosed = isClosed; var path = new Path { Data = new PathGeometry { Figures = figures }, Style = mg.ContentControl.UnframedLine }; if (mg.StencilType == "ObstacleRestrictedArea") { path.Fill = HatchBrush(mg.ContentControl.Brush); } #if WINDOWS_UWP path.SetBinding(Shape.StrokeThicknessProperty, new Binding() { Path = new PropertyPath("LineThickness"), Source = mg.ContentControl }); #else path.SetBinding(Shape.StrokeThicknessProperty, new Binding("LineThickness") { Source = mg.ContentControl }); #endif return(path); }
/// <summary> /// Generates the correct combination of task force, installation, and feint dummy for a symbol. /// </summary> /// <param name="ms"> /// The symbol to which the generated rendering is attached. /// </param> /// <param name="symbolCode"> /// The symbol code for the given symbol /// </param> /// <returns> /// The maximum height of the generated rendering. /// </returns> internal static double Generate(MilSymbol ms, string symbolCode) { // This is the maximum height generated by this combination of pieces Rect r = ms.BaseRect; if (r.IsEmpty) { return(0); } double height = r.Top; if (!SymbolData.Check(ref symbolCode)) { return(height); } char code = ModifierCode.GetCode(symbolCode); switch (code) { case ModifierCode.Headquarters: // headquarters ms.AddChild("HQ", GenerateHeadquarters(ms)); break; case ModifierCode.TaskForceHeadquarters: // task force, headquarters ms.AddChild("TF", GenerateTaskForce(ms, out height)); ms.AddChild("HQ", GenerateHeadquarters(ms)); break; case ModifierCode.FeintDummyHeadquarters: // feint dummy, headquarters ms.AddChild("FD", GenerateFeintDummy(ms, ref height)); ms.AddChild("HQ", GenerateHeadquarters(ms)); break; case ModifierCode.FeintDummyTaskForceHeadquarters: // feint dummy, task force, headquarters ms.AddChild("TF", GenerateTaskForce(ms, out height)); ms.AddChild("FD", GenerateFeintDummy(ms, ref height)); ms.AddChild("HQ", GenerateHeadquarters(ms)); break; case ModifierCode.TaskForce: // task force ms.AddChild("TF", GenerateTaskForce(ms, out height)); break; case ModifierCode.FeintDummy: // feint dummy ms.AddChild("FD", GenerateFeintDummy(ms, ref height)); break; case ModifierCode.FeintDummyTaskForce: // feint dummy/task force ms.AddChild("TF", GenerateTaskForce(ms, out height)); ms.AddChild("FD", GenerateFeintDummy(ms, ref height)); break; case ModifierCode.Installation: // installation ms.AddChild("Installation", GenerateInstallation(ms, out height)); // There is an unfortunate overloading of the echelon character in the standard if (Echelon.GetCode(symbolCode) == 'B') { ms.AddChild("FD", GenerateFeintDummy(ms, ref height)); } break; case ModifierCode.Mobility: // mobility case ModifierCode.Towed: // towed break; } return(height); }
/// <summary> /// Stop all services and dispose of them. This should be called once before the game /// exits. It can be called repeatedly to destroy re-created resources. /// </summary> public static void StopAllServices() { try { Game.Dispose(); } catch (Exception) { } finally { Game = null; } try { Resources.Dispose(); } catch (Exception) { } finally { Resources = null; } StateManager = null; try { Echelon.Dispose(); } catch (Exception) { } finally { Echelon = null; } try { Theater.Dispose(); } catch (Exception) { } finally { Theater = null; } try { AudioManager.Dispose(); } catch (Exception) { } finally { AudioManager = null; } try { MP3Player.Dispose(); } catch (Exception) { } finally { MP3Player = null; } try { Logger.Close(); } catch (Exception) { } finally { Logger = null; } }