/// <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> /// Normalize here strictly means "what will the templates understand?" which is mostly air, land, and water. /// </summary> /// <param name="symbolCode"> /// The symbol code. /// </param> /// <returns> /// The enumerated battle dimension value. /// </returns> private static int NormalizeBattleDimension(string symbolCode) { if (!Check(ref symbolCode)) { return(0); } int bd = CategoryBattleDimension.GetCode(symbolCode); if (bd == CategoryBattleDimension.BdUnknown) { return(CategoryBattleDimension.BdSeaSurface); } return(bd); }
/// <summary> /// Returns the arrow representing a direction of travel for a mil symbol /// </summary> /// <param name="symbolCode">Code for the mil symbol</param> /// <param name="labels">The labels for the symbol, we're looking for "Q"</param> /// <param name="extraOffset">An extra offset for tactical graphics</param> /// <returns>The arrow shape representing the direction of travel</returns> internal static Shape GenerateQ( string symbolCode, IDictionary <string, string> labels, double extraOffset) { if (!SymbolData.Check(ref symbolCode)) { return(null); } string q; if (!labels.TryGetValue("Q", out q)) { return(null); } double angle; if (!double.TryParse(q, out angle)) { return(null); } double off = 0.0; if (CategoryBattleDimension.GetCode(symbolCode) == CategoryBattleDimension.BdGround) { off = SymbolData.GetBounds(symbolCode).Bottom; } off += extraOffset; return(new Path { Style = SymbolData.GetStyle("BS10"), Data = new PathGeometry { Figures = new PathFigureCollection { GenerateArrowPoints(off, angle) } } }); }
public void BattleDimensionTest() { int gc = CategoryBattleDimension.GetCode(string.Empty); Assert.AreEqual(gc, 0); gc = CategoryBattleDimension.GetCode(null); Assert.AreEqual(gc, 0); gc = CategoryBattleDimension.GetCode("qqqqqqqqqqqqqqq"); Assert.AreEqual(gc, 0); string str = CategoryBattleDimension.GetName(string.Empty); Assert.AreEqual(str, string.Empty); str = CategoryBattleDimension.GetName(null); Assert.AreEqual(str, string.Empty); str = CategoryBattleDimension.GetName("qqqqqqqqqqqqqqq"); Assert.AreEqual(str, string.Empty); str = CategoryBattleDimension.GetName("iqpqqqqqqqqqqqq"); Assert.AreEqual(str, "Space"); }
/// <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> /// When is the top of the symbol flat? /// Answer: /// 1. normalize StandardIdentity to 'F', 'H', 'N' or 'U' /// 2. return true when it is Subsurface /// 3. return true when it is Neutral /// 4. return true when it is Friendly Units, Installations, or SOF /// 5. return true when it is Friendly Emergency Operations /// a. technically, friendly emergency equipment is not flat /// </summary> /// <param name="symbolCode"> /// The symbol code to check for a flat top to the symbol. /// </param> /// <returns> /// Returns a boolean to indicate whether the top of the symbol is flat. /// </returns> internal static bool IsTopFlat(string symbolCode) { if (!Check(ref symbolCode)) { return(false); } int dimensionKey = CategoryBattleDimension.GetCode(symbolCode); if (dimensionKey == CategoryBattleDimension.BdSubsurface) { return(true); } int identityKey = StandardIdentity.GetNormalizedStandardIdentity(symbolCode); if (identityKey == StandardIdentity.Neutral) { return(true); } if (identityKey == StandardIdentity.Friend) { if (dimensionKey == CategoryBattleDimension.BdSpace || dimensionKey == CategoryBattleDimension.BdAir || dimensionKey == CategoryBattleDimension.BdSeaSurface || dimensionKey == CategoryBattleDimension.BdUnknown) { return(false); } if (IsEquipment(symbolCode)) { return(false); } 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> /// Adds the black ribbon at the top of the symbol for the standard identity "Space". /// </summary> /// <param name="symbolCode">The symbol code for the space entity.</param> /// <returns>The shape representing the black ribbon overlay for a space entity.</returns> internal static Shape GenerateSpace(string symbolCode) { if (!SymbolData.Check(ref symbolCode)) { return(null); } if (CategoryBattleDimension.GetCode(symbolCode) != CategoryBattleDimension.BdSpace) { return(null); } // Handy points for future reference // Inside for unknown ground // <Path Data="F0 M-61,-140 C-30,-175 30,-175 61,-140" /> // Inside for hostile ground // <Polygon Points="-61,-105 0,-166 61,-105" /> switch (StandardIdentity.GetNormalizedStandardIdentity(symbolCode)) { case StandardIdentity.Friend: { return(GenerateBlackSpline( new Point(-61, -107), new Point(-23, -148), new Point(23, -148), new Point(61, -107))); } case StandardIdentity.Unknown: { return(GenerateBlackSpline( new Point(-61, -117), new Point(-30, -160), new Point(30, -160), new Point(61, -117))); } case StandardIdentity.Hostile: { return(new Path { Fill = new SolidColorBrush(Colors.Black), Data = new PathGeometry { Figures = new PathFigureCollection { new PathFigure { StartPoint = new Point(-61, -93), Segments = new PathSegmentCollection { new LineSegment { Point = new Point(0, -149) }, new LineSegment { Point = new Point(61, -93) } } } } } }); } case StandardIdentity.Neutral: { return(new Path { Fill = new SolidColorBrush(Colors.Black), Data = new PathGeometry { Figures = new PathFigureCollection { new PathFigure { StartPoint = new Point(-127, -104), Segments = new PathSegmentCollection { new LineSegment { Point = new Point(127, -104) }, new LineSegment { Point = new Point(127, -139) }, new LineSegment { Point = new Point(-127, -139) } } } } } }); } } return(null); }
/// <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> /// Generate the installation rendering for the passed in symbol. /// </summary> /// <param name="ms"> /// The military symbol for which to provide the installation rendering. /// </param> /// <param name="height"> /// The height at which to provide the installation rendering. /// </param> /// <returns> /// The graphics Shape object that represents the installation rendering. /// </returns> private static Shape GenerateInstallation(MilSymbol ms, out double height) { //// U&PGW ZSGF full unknown (flat) //// AP full air (not flat) //// U subsurface (flat) //// N&L ZSGF full neutral (flat) //// AP full air (flat) //// U subsurface (flat) //// H&S ZSGF full hostile (not flat) //// AP full air (not flat) //// U subsurface (flat) //// F&ADMJK Z(IG)S full friendly (not flat) //// F(~IG) full friendly (flat) //// AP full air (not flat) //// U subsurface (flat) height = -185; Brush br = new SolidColorBrush(Colors.Black); int si = StandardIdentity.GetNormalizedStandardIdentity(ms.SymbolCode); if (SymbolData.IsTopFlat(ms.SymbolCode)) { double t = ms.BaseRect.Top; if (si == StandardIdentity.Unknown) { t += SymbolData.HalfWidth; } height = t - 30; return(GenericInstallation(br, height, t)); } int bd = CategoryBattleDimension.GetCode(ms.SymbolCode); bool ap = bd == CategoryBattleDimension.BdSpace || bd == CategoryBattleDimension.BdAir; // The cases cover those surfaces which are flat on top versus those that are not switch (si) { case StandardIdentity.Unknown: // Outside for unknown space if (ap) { return(UnknownSpaceInstallation(br, height)); } return(UnknownGroundInstallation(br, height)); case StandardIdentity.Hostile: // Outside for hostile space if (ap) { height = -165; return(HostileSpaceInstallation(br, height)); } return(HostileGroundInstallation(br, height)); case StandardIdentity.Friend: height = -175; // Outside for friendly space if (ap) { return(FriendSpaceInstallation(br, height)); } return(FriendCircleInstallation(br, height)); } return(null); }
/// <summary> /// Generate the task force rendering for the passed in symbol. /// </summary> /// <param name="ms"> /// The military symbol for which to provide the task force rendering. /// </param> /// <param name="height"> /// The height at which to provide the task force rendering. /// </param> /// <returns> /// The graphics Path object that represents the task force rendering. /// </returns> private static Path GenerateTaskForce(MilSymbol ms, out double height) { height = -185; double bottom = 0; const double Wide = 54; int si = StandardIdentity.GetNormalizedStandardIdentity(ms.SymbolCode); if (SymbolData.IsTopFlat(ms.SymbolCode)) { bottom = ms.BaseRect.Top; if (si == StandardIdentity.Unknown) { bottom += SymbolData.HalfWidth; } height = bottom - 75; } else { int bd = CategoryBattleDimension.GetCode(ms.SymbolCode); bool ap = bd == CategoryBattleDimension.BdSpace || bd == CategoryBattleDimension.BdAir; // The cases cover those surfaces which are flat on top versus those that are not switch (si) { case StandardIdentity.Unknown: if (ap) { height = -230; // space bottom = -133; } else { height = -250; // ground bottom = -154; } break; case StandardIdentity.Hostile: if (ap) { height = -230; // space bottom = -107; } else { height = -253; // ground bottom = -119; } break; case StandardIdentity.Friend: height = -222; if (ap) { bottom = -121; // space } else { bottom = -137; // ground circles } break; } } return(new Path { Style = SymbolData.GetStyle("BS10"), Data = new PathGeometry { Figures = new PathFigureCollection { new PathFigure { StartPoint = new Point(Wide, bottom), Segments = new PathSegmentCollection { new LineSegment { Point = new Point(Wide, height) }, new LineSegment { Point = new Point(-Wide, height) }, new LineSegment { Point = new Point(-Wide, bottom) } } } } } }); }