/// <summary> /// Takes the symbol code and matches one of the stencils in the resource dictionary. /// </summary> /// <param name="symbolCode"> /// The symbol code for which to look up the stencil. /// </param> /// <returns> /// The string that should be used to get the ResourceDictionary entry for this symbol. /// </returns> public static string CodeToStencil(string symbolCode) { if (!SymbolData.Check(ref symbolCode)) { return(null); } int schemeKey = CodingScheme.GetCode(symbolCode); // Weather short circuits most considerations, at least for now if (schemeKey == CodingScheme.Weather) { return(symbolCode); } string stencil = symbolCode.Substring(0, 10).ToUpperInvariant(); int dash = stencil.IndexOf('-', 4); if (dash > 0) { stencil = stencil.Substring(0, dash); } // Replace remaining '-'s with '_'s stencil = stencil.Replace('-', '_'); // Return one of the four (approximately) that we know about int identityKey = StandardIdentity.GetNormalizedStandardIdentity(symbolCode); // Need the battle dimension int dimensionKey = CategoryBattleDimension.GetCode(symbolCode); // If we have a Z battle dimension cut right to the chase. // Get a blank stencil so we can add a question mark. if (dimensionKey == CategoryBattleDimension.BdUnknown) { return("I" + StandardIdentity.ToChar(identityKey) + "ZP"); } string tail = stencil.Substring(2, 1) + "P" + stencil.Substring(4); // If we have EmergenctManagement and a NaturalEvent, get rid of the standard identity // or if we have a tactical graphic, get rid of the standard identity if ((schemeKey == CodingScheme.EmergencyManagement && dimensionKey == CategoryBattleDimension.EmNaturalEvents) || schemeKey == CodingScheme.TacticalGraphics) { return(stencil.Substring(0, 1) + "_" + tail); } // If framed, we'll include the base affiliation if (dimensionKey != CategoryBattleDimension.BdOther) { return(stencil.Substring(0, 1) + StandardIdentity.ToChar(identityKey) + tail); } // Otherwise, we're looking for an unframed element return(stencil.Substring(0, 1) + "." + tail); }
/// <summary> /// Process the given appendix. /// </summary> /// <param name="append"> /// The name of the appendix. /// </param> /// <param name="framed"> /// Whether or not the symbols are framed. /// </param> private void ProcessSymbolCollection(string append, bool framed) { const double Scale = 1.0; // Since some appendices cross reference symbols, // in other appendices, we'll check to make sure // we haven't already drawn a particular symbol code. IList <string> symList = new List <string>(); var affiliations = new[] { "U", "F", "N", "H" }; var keys = MilAppendix.Keys(append); foreach (var ap in keys) { MilSymbol ms; var sc = ap; if (symList.Contains(sc)) { continue; } symList.Add(sc); // There is no affiliation for weather var schemeKey = CodingScheme.GetCode(sc); if (schemeKey == CodingScheme.Weather) { ms = new MilSymbol(sc, Scale, "X=67.8"); this.ProcessSymbol(ms, sc); continue; } if (schemeKey == CodingScheme.TacticalGraphics) { sc = sc.Substring(0, 1) + "H" + sc.Substring(2, 1) + "A" + sc.Substring(4); ms = new MilSymbol(sc, Scale, "H=HH;H1=H1;W=W;W1=W1;T=TT;N=N;X=XX;V=VV;C=CC;Y=YY;Q=-60.0"); this.ProcessSymbol(ms, sc); continue; } if (!framed) { sc = sc.Substring(0, 2) + "X" + sc.Substring(3); } foreach (var c in affiliations) { sc = sc[0] + c + sc[2] + "P" + sc.Substring(4, 10) + "E"; ms = new MilSymbol(sc, Scale, null, null); this.ProcessSymbol(ms, sc); } } }
public void CodingSchemeTest() { int gc = CodingScheme.GetCode(string.Empty); Assert.AreEqual(gc, 0); gc = CodingScheme.GetCode(null); Assert.AreEqual(gc, 0); gc = CodingScheme.GetCode("qqqqqqqqqqqqqqq"); Assert.AreEqual(gc, 0); string str = CodingScheme.GetName(string.Empty); Assert.AreEqual(str, string.Empty); str = CodingScheme.GetName(null); Assert.AreEqual(str, string.Empty); str = CodingScheme.GetName("qqqqqqqqqqqqqqq"); Assert.AreEqual(str, string.Empty); str = CodingScheme.GetName("gqpqqqqqqqqqqqq"); Assert.AreEqual(str, "Tactical Graphics"); }
/// <summary> /// Determine once and for all if a symbol code is for a piece of equipment. /// </summary> /// <param name="symbolCode"> /// The symbol code. /// </param> /// <returns> /// A boolean indicating if the symbol code represents equipment. /// </returns> internal static bool IsEquipment(string symbolCode) { if (!Check(ref symbolCode)) { return(false); } var schemeKey = CodingScheme.GetCode(symbolCode); if (schemeKey == CodingScheme.Intelligence) { return(true); } var func = symbolCode.Substring(4, 6).Trim(new[] { '-' }); if (schemeKey == CodingScheme.Warfighting && !string.IsNullOrEmpty(func) && func[0] == 'E') { return(true); } if (schemeKey == CodingScheme.EmergencyManagement) { var catKey = CategoryBattleDimension.GetCode(symbolCode); if (catKey == CategoryBattleDimension.EmOperations && EmOperationsEquipment.Contains(func)) { return(true); } if (catKey == CategoryBattleDimension.EmInfrastructure && EmInfrastructureEquipment.Contains(func)) { return(true); } } return(false); }
/// <summary> /// Writes out the CXML file. /// </summary> /// <param name="ms"> /// The symbol for which to generate the CXML. /// </param> /// <param name="rootName"> /// The name to use for the symbol. /// </param> private void WriteCxml(MilSymbol ms, string rootName) { var symbolCode = (CodingScheme.GetCode(ms.SymbolCode) != CodingScheme.Weather) ? rootName + "*****" : ms.SymbolCode; var description = MilAppendix.Description(symbolCode); var lines = description.Split(new[] { '\n' }); var lineCount = lines.Length - 1; // the last line is empty var sb = new StringBuilder(); sb.AppendFormat(@"<Item Id=""{0}"" Name=""{1}"" Img=""Symbols\{1}.png"" Href="""">", this.index++, rootName); sb.AppendLine(); if (lineCount > 0) { sb.AppendFormat(@" <Description>""{0}""</Description>", lines[lineCount - 1].Trim(new[] { ' ', '\n', '\r' })); sb.AppendLine(); } else { sb.AppendFormat(@" <Description>""""</Description>"); sb.AppendLine(); } sb.AppendLine(@" <Facets>"); sb.AppendLine(@" <Facet Name=""Affiliation"">"); sb.AppendFormat(@" <String Value=""{0}"" />", StandardIdentity.GetName(symbolCode)); sb.AppendLine(); sb.AppendLine(@" </Facet>"); sb.AppendLine(@" <Facet Name=""Battle Dimension"">"); sb.AppendFormat(@" <String Value=""{0}"" />", CategoryBattleDimension.GetName(symbolCode)); sb.AppendLine(); sb.AppendLine(@" </Facet>"); if (lineCount > 2) { sb.AppendLine(@" <Facet Name=""Type"">"); sb.AppendFormat(@" <String Value=""{0}"" />", lines[2].Trim(new[] { ' ', '\n', '\r' })); sb.AppendLine(); sb.AppendLine(@" </Facet>"); } sb.AppendLine(@" <Facet Name=""Coding Scheme"">"); sb.AppendFormat(@" <String Value=""{0}"" />", CodingScheme.GetName(symbolCode)); sb.AppendLine(); sb.AppendLine(@" </Facet>"); if (lineCount - 1 > 3) { sb.AppendLine(@" <Facet Name=""Key Phrases"">"); for (var i = 3; i < lineCount - 1; i++) { sb.AppendFormat(@" <String Value=""{0}"" />", lines[i].Trim(new[] { ' ', '\n', '\r' })); sb.AppendLine(); } sb.AppendLine(@" </Facet>"); } sb.AppendLine(@" </Facets>"); sb.AppendLine(@"</Item>"); #if DO_WRITES this.cxmlStream.Write(sb.ToString()); #endif }
/// <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> /// Selectively (re)generates labels. /// </summary> /// <param name="styles"> /// An optional list of styles to apply to the labels. /// </param> private void GenerateLabels(IList <Style> styles) { try { if (this.suppressRefresh) { return; } string symbolCode = this.SymbolCode; if (symbolCode == null) { return; } if (this.labels == null) { return; } if (styles == null) { styles = MilLabels.GetStyles(this.LabelStyle); } this.IsDirty = true; int schemeKey = CodingScheme.GetCode(symbolCode); if (schemeKey == CodingScheme.Weather) { // All extraneous information for weather is in the labels. MilLabels.GenerateWeather(symbolCode, this.labels, this.AddChild); return; } if (schemeKey == CodingScheme.TacticalGraphics) { MilLabels.GenerateTacticalGraphics( symbolCode, this.labels, styles[MilLabels.TacticalGraphicsLabels], this.AddChild); return; } // Generate labels to the left of the symbol this.AddChild("Left", MilLabels.GenerateLeft(symbolCode, this.labels, styles[MilLabels.LeftLabels])); // Generate labels to the right of the symbol this.AddChild("Right", MilLabels.GenerateRight(symbolCode, this.labels, styles[MilLabels.RightLabels])); // This is just the quantity, if specified this.AddChild("Top", MilLabels.GenerateTop(this.high, symbolCode, this.labels, styles[MilLabels.TopLabels])); // This is just the C2 headquarters label this.AddChild("Middle", MilLabels.GenerateMiddle(symbolCode, this.labels)); // This is the direction of movement (which apparently requires a label value) this.AddChild("Q", MilLabels.GenerateQ(symbolCode, this.labels, 0.0)); } catch (Exception ex) { Log.WriteMessage(LogLevel.Error, "Unable to add labels to symbol", ex); } }
/// <summary> /// Initializes a new instance of the <see cref="MilSymbolBase"/> class. /// </summary> /// <param name="symbolCode"> /// The symbol code for this symbol. /// </param> /// <param name="lineBrush"> /// An optional line brush for outlining the symbol. /// </param> /// <param name="fillBrush"> /// An optional fill brush for filling the symbol's background. /// </param> public MilSymbolBase(string symbolCode, Brush lineBrush, Brush fillBrush) { if (symbolCode == null) { this.empty = true; return; } string stencil = CodeToStencil(symbolCode); if (MilAppendix.NoTemplate(stencil)) { this.empty = true; return; } this.DataContext = this; // Will need to treat weather and tactical graphics carefully int schemeKey = CodingScheme.GetCode(symbolCode); if (schemeKey == CodingScheme.Weather) { // These symbols can change color - so we bind to Line and Fill if (symbolCode.StartsWith("WAS-WSTS")) { if (lineBrush == null) { lineBrush = MilBrush.Rust; } if (fillBrush == null) { fillBrush = MilBrush.Rust; } this.SetLines(lineBrush); this.SetLineFills(lineBrush, fillBrush); } this.Template = SymbolData.GetControlTemplate(stencil); // gets the template - the main thing this.empty = this.Template == null; if (!this.empty) { this.SetLimits(symbolCode); } return; } // If the standard identity (StandardIdentity) is some type of pending, we'll need the // anticipated (dashhed) outline for the frame. this.needDashed = SymbolData.IsDashed(symbolCode); // There are occasions when we need a line style that matches affiliation and present int dimensionKey = CategoryBattleDimension.GetCode(symbolCode); bool needUnframed = schemeKey == CodingScheme.TacticalGraphics || dimensionKey == CategoryBattleDimension.BdOther || (schemeKey == CodingScheme.Warfighting && dimensionKey == CategoryBattleDimension.BdSubsurface); if (needUnframed) { this.unframedLine = MilBrush.GetLinePresent(MilBrush.FindColorScheme(symbolCode)); this.SetUnframedLines(lineBrush); } this.SetLines(lineBrush); // Get a brush style if user didn't specify if (fillBrush == null) { fillBrush = MilBrush.FindColorScheme(symbolCode); } if (needUnframed) { this.SetUnframedLineFills(fillBrush); } this.SetLineFills(lineBrush, fillBrush); this.Template = SymbolData.GetControlTemplate(stencil); // gets the template - the main thing this.empty = this.Template == null; if (!this.empty) { this.SetLimits(symbolCode); } }
/// <summary> /// Plots all of the core symbols that are in Appendix D. /// Since not all symbol codes are non-blank, there are some blanks in the output. /// Refer to MIL-STD 2525C for comparison. /// </summary> /// <param name="append"> /// The appendix from which to get the symbols. /// </param> /// <param name="framed"> /// Whether or not the symbols are framed. /// </param> private static void PlotAllSymbols(string append, bool framed) { Canvas cv = GetCanvas(); if (cv == null) { return; } // Since some appendices cross reference symbols, // in other appendices, we'll check to make sure // we haven't already drawn a particular symbol code. IList <string> symList = new List <string>(); double x = Edge; double y = Edge; var affiliations = new[] { "U", "F", "N", "H" }; bool first = true; var keys = MilAppendix.Keys(append); foreach (string ap in keys) { string sc = ap; if (symList.Contains(sc)) { continue; } symList.Add(sc); // There is no affiliation for weather int schemeKey = CodingScheme.GetCode(sc); if (schemeKey == CodingScheme.Weather) { // Check centering // var ls1 = new Line { X1 = x + 5, Y1 = y + 5, X2 = x - 5, Y2 = y - 5, Stroke = new SolidColorBrush(Colors.Red), StrokeThickness = 1 }; // var ls2 = new Line { X1 = x - 5, Y1 = y + 5, X2 = x + 5, Y2 = y - 5, Stroke = new SolidColorBrush(Colors.Red), StrokeThickness = 1 }; // cv.Children.Add(ls1); // cv.Children.Add(ls2); var ms = new MilSymbol(sc, Scale, "X=67.8"); DrawSymbol(cv, ms, x, y); if ((x += Tight) > 12 * Tight) { x = Edge; y += Tight; } continue; } if (schemeKey == CodingScheme.TacticalGraphics) { // Check centering // var ls1 = new Line { X1 = x + 5, Y1 = y + 5, X2 = x - 5, Y2 = y - 5, Stroke = new SolidColorBrush(Colors.Red), StrokeThickness = 1 }; // var ls2 = new Line { X1 = x - 5, Y1 = y + 5, X2 = x + 5, Y2 = y - 5, Stroke = new SolidColorBrush(Colors.Red), StrokeThickness = 1 }; // cv.Children.Add(ls1); // cv.Children.Add(ls2); sc = sc.Substring(0, 1) + "H" + sc.Substring(2, 1) + "A" + sc.Substring(4); var ms = new MilSymbol(sc, Scale, "H=HH;H1=H1;W=W;W1=W1;T=TT;N=N;X=XX;V=VV;C=CC;Y=YY;Q=-60.0"); DrawSymbol(cv, ms, x, y); if ((x += Tight) > 12 * Tight) { x = Edge; y += Tight + 25; } continue; } if (!framed) { sc = sc.Substring(0, 2) + "X" + sc.Substring(3); } foreach (string c in affiliations) { sc = sc[0] + c + sc[2] + "C" + sc.Substring(4, 10) + "E"; var ms = new MilSymbol(sc, Scale, null, null); if (first && ms.Empty) { continue; } first = false; DrawSymbol(cv, ms, x, y); if ((x += Tight) > 12 * Tight) { x = Edge; y += Tight; } } } }